Repositori ini menawarkan server login untuk digunakan dengan alat pemetaan Cocoda. Ini memungkinkan pengguna untuk mengotentikasi menggunakan penyedia yang berbeda (misalnya GitHub, ORCID). Lihat https://coli-conc.gbv.de/login/api untuk contoh tentang bagaimana Anda bisa menggunakan ini.
.envproviders.jsonapplications.jsonLogin-Server membutuhkan node.js (> = V18, V20 disarankan) dan akses ke database MongoDB (> = V5, V7 direkomendasikan).
git clone https://github.com/gbv/login-server.git
cd login-server
npm install
# after setting up or changing providers, create indexes
npm run indexesLogin-Server juga tersedia melalui Docker. Silakan merujuk ke dokumentasi di https://github.com/gbv/login-server/blob/master/docker/readme.md untuk lebih jelasnya.
Jika menjalankan server di belakang proxy terbalik, pastikan untuk memasukkan header X-Forwarded-Proto , izinkan semua metode HTTP, dan aktifkan proxying Websocket.
Anda perlu menyediakan dua file konfigurasi:
.envUntuk mengonfigurasi aplikasi:
# recommended, port for express, default: 3004
PORT=
# recommended, full base URL, default: http://localhost[:PORT]/
# (required when used in production or behind a reverse proxy)
BASE_URL=
# title of application (will be shown in header)
TITLE=My Login Server
# list of allowed origins separated by comma, includes the hostname of BASE_URL by default
ALLOWED_ORIGINS=
# required for some strategies to enable production mode, default: development
NODE_ENV=production
# strongly recommended, imprint and privacy URLs for footer and clients
IMPRINT_URL=
PRIVACY_URL=
# recommended, secret used by the session
SESSION_SECRET=
# optional, maximum number of days a session is valid (rolling), default: 30
COOKIE_MAX_DAYS=
# threshold in minutes when to send "sessionAboutToExpire" events, default: 60
SESSION_EXPIRATION_MESSAGE_THRESHOLD=
# interval in minutes in which to check for expiring sessions, default: 5
SESSION_EXPIRATION_MESSAGE_INTERVAL=
# username used for MongoDB, default: <empty>
MONGO_USER=
# password used for MongoDB, default: <empty>
MONGO_PASS=
# host used for MongoDB, default: 127.0.0.1
MONGO_HOST=
# port used for MongoDB, default: 27017
MONGO_PORT=
# database used for MongoDB, default: login-server
MONGO_DB=
# the rate limit window in ms, default: 60 * 1000
RATE_LIMIT_WINDOW=
# the rate limit tries, default: 10
RATE_LIMIT_MAX=
# a jsonwebtoken compatible keypair
JWT_PRIVATE_KEY_PATH=
JWT_PUBLIC_KEY_PATH=
# the jsonwebtoken algorithm used
JWT_ALGORITHM=
# expiration time of JWTs in seconds, default: 120, min: 10
JWT_EXPIRES_IN=
# URL for Sources, default: https://github.com/gbv/login-server
SOURCES_URL=
# the path to the providers.json file, default: ./providers.json
PROVIDERS_PATH=
# log = log all messages, warn = only log warnings and errors, error = only log errorsl default: log
VERBOSITY=providers.jsonUntuk mengonfigurasi penyedia. Lihat Penyedia.
applications.json Untuk memberikan informasi kepada pengguna tentang aplikasi mana yang mengakses data mereka, dan aplikasi mana yang memprakarsai login sesi, Anda dapat memberikan daftar aplikasi di applications.json . Daftar ini harus berupa array objek dan setiap objek harus memiliki url dan name . Contoh:
[
{
"url" : " https://bartoc.org " ,
"name" : " BARTOC "
},
{
"url" : " https://coli-conc.gbv.de/coli-rich/ " ,
"name" : " coli-rich "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/app/ " ,
"name" : " Cocoda "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/dev/ " ,
"name" : " Cocoda (dev) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/rvk/ " ,
"name" : " Cocoda (RVK) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/wikidata/ " ,
"name" : " Cocoda (Wikidata) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/ " ,
"name" : " Cocoda (other) "
},
{
"url" : " https://coli-conc.gbv.de " ,
"name" : " Other coli-conc application "
}
] URL harus dapat diakses karena antarmuka akan terhubung ke sana. Sesi dikaitkan dengan aplikasi jika URL pengirimnya berisi url aplikasi. Aplikasi akan diperiksa dari atas ke bawah, jadi Anda harus memesannya dari URL paling spesifik ke URL tertentu (lihat contoh di atas).
npm run startServer menyediakan antarmuka web, API HTTP dan Websocket.
Antarmuka web memungkinkan pengguna untuk membuat dan mengelola akun dengan koneksi ke banyak identitas di penyedia identitas (lihat penyedia). Penyedia digunakan untuk mengotentikasi pengguna karena server login tidak menyimpan kata sandi apa pun (masuk tunggal).
HTTP API dan WebSocket memungkinkan aplikasi klien untuk berinteraksi dengan server login, misalnya untuk memeriksa apakah pengguna telah masuk dan untuk mengetahui identitas mana yang termasuk dalam pengguna (lihat login-klien dan login-klien-vue untuk perpustakaan JavaScript untuk menghubungkan aplikasi web dengan server login).
Server login selanjutnya dapat digunakan untuk mengotentikasi pengguna terhadap layanan lain sehingga pengguna dapat membuktikan identitas mereka.
Direktori bin berisi skrip penolong untuk administrasi instance server seperti mencantumkan akun pengguna dan mengelola penyedia lokal.
Tes menggunakan mongoDB yang sama seperti yang dikonfigurasi dalam .env , hanya dengan -test postfix setelah nama database.
npm test Login-Server menggunakan Passport (GitHub) sebagai Middleware Otentikasi. Paspor menggunakan apa yang disebut "strategi" untuk mendukung otentikasi dengan penyedia yang berbeda. Daftar strategi yang tersedia dapat ditemukan di sini. Strategi yang saat ini didukung dalam server login adalah:
Karena strategi menggunakan parameter yang berbeda dalam callback verifikasi mereka, setiap strategi memiliki file pembungkusnya sendiri dalam strategies/ . Untuk menambahkan strategi lain ke server login, tambahkan file yang disebut {name}.js (di mana {name} adalah nama strategi yang digunakan dengan passport.authenticate ) dengan struktur berikut (github sebagai contoh):
/**
* OAuth Stategy for GitHub.
*/
// Import strategy here
import { Strategy } from "passport-github"
// Don't change this part!
export default ( options , provider , callback ) => new Strategy ( options ,
// Strategies have different callback parameters.
// `req` is always the first and the `done` callback is always last.
( req , token , tokenSecret , profile , done ) => {
// Prepare a standardized object for the user profile,
// usually using information from the `profile` parameter
let providerProfile = {
// Required, don't change this!
provider : provider . id ,
// Required: Choose a field that represents a unique user ID for this user
id : profile . id ,
// Optional: Provides a display name (e.g. full name)
name : profile . displayName ,
// Optional: Provides a username
username : profile . username
}
// Call a custom callback. `req`, `providerProfile`, and `done` are required,
// `token` and `tokenSecret` can be null.
callback ( req , token , tokenSecret , providerProfile , done )
} )Anda dapat melihat strategi yang ada sebagai contoh dan menambahkan sendiri melalui permintaan tarik.
Setelah Anda menambahkan strategi, Anda dapat menggunakannya dengan menambahkan penyedia ke providers.json .
[
{
"id" : " github " ,
"strategy" : " github " ,
"name" : " GitHub " ,
"template" : " https://github.com/{username} " ,
"options" : {
"clientID" : " abcdef1234567890 " ,
"clientSecret" : " abcdef1234567890abcdef1234567890 "
},
"image" : " https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg " ,
"url" : " https://github.com "
}
]Setiap objek dalam daftar penyedia dapat memiliki properti berikut:
id (wajib) - ID unik untuk penyedia.strategy (wajib) - Nama strategi paspor yang digunakan oleh penyedia.name (Diperlukan) - Tampilan nama penyedia.template (Opsional) - String template untuk menghasilkan URI (placeholder {field} dapat berupa bidang apa pun yang disediakan dalam objek providerProfile , biasanya {id} atau {username} ).credentialsNecessary (Opsional) - Setel ke true jika nama pengguna dan kredensial kata sandi diperlukan untuk penyedia ini. Alih-alih pengalihan (untuk oAuth), server login akan menunjukkan formulir login yang akan mengirim kredensial ke titik akhir pos.options (sebagian besar diperlukan) - Opsi Opsi untuk Strategi, sering kali berisi kredensial klien untuk titik akhir otentikasi.image (Opsional) - Gambar yang terkait dengan penyedia. Akan ditampilkan di halaman login dan dalam daftar identitas yang terhubung. Anda dapat memberikan gambar statis di folder static/ . Nilai untuk properti kemudian akan static/myimage.svg . Jika nama file cocok dengan id penyedia, gambar akan secara otomatis terkait.url (Opsional) - URL untuk penyedia; akan ditautkan pada gambar /ikonnya di bawah /account . Ada URL default untuk strategi github , orcid , mediawiki , dan stackexchange . Berikut ini adalah contoh providers.json yang menunjukkan cara mengkonfigurasi masing -masing penyedia yang ada:
[
{
"id" : " github " ,
"strategy" : " github " ,
"name" : " GitHub " ,
"template" : " https://github.com/{username} " ,
"options" : {
"clientID" : " abcdef1234567890 " ,
"clientSecret" : " abcdef1234567890abcdef1234567890 "
}
},
{
"id" : " orcid " ,
"strategy" : " orcid " ,
"name" : " ORCID " ,
"template" : " https://orcid.org/{id} " ,
"options" : {
"clientID" : " APP-abcdef1234567890 " ,
"clientSecret" : " abcdef1-23456-7890ab-cdef12-34567890 "
}
},
{
"id" : " mediawiki " ,
"strategy" : " mediawiki " ,
"name" : " Mediawiki " ,
"template" : " https://www.mediawiki.org/wiki/User:{username} " ,
"options" : {
"consumerKey" : " abcdef1234567890 " ,
"consumerSecret" : " abcdef1234567890abcdef1234567890 "
}
},
{
"id" : " stackexchange " ,
"strategy" : " stackexchange " ,
"name" : " Stack Exchange " ,
"template" : " https://stackexchange.com/users/{id} " ,
"options" : {
"clientID" : " 12345 " ,
"clientSecret" : " abcdef1234567890(( " ,
"stackAppsKey" : " 1234567890abcdefg(( "
}
},
{
"id" : " my-ldap " ,
"strategy" : " ldapauth " ,
"name" : " My LDAP " ,
"credentialsNecessary" : true ,
"options" : {
"server" : {
"url" : " ldap://ldap.example.com " ,
"bindDN" : " uid=admin,dc=example,dc=com " ,
"bindCredentials" : " abcdef1234567890 " ,
"searchBase" : " dc=example,dc=com " ,
"searchFilter" : " (uid={{username}}) "
}
}
},
{
"id" : " easydb " ,
"name" : " easydb test provider " ,
"strategy" : " easydb " ,
"credentialsNecessary" : true ,
"options" : {
"url" : " https://easydb5-test.example.com/api/v1/ "
}
},
{
"id" : " some-script " ,
"strategy" : " script " ,
"name" : " Some Script " ,
"credentialsNecessary" : true ,
"template" : " https://example.org/some-script/{id} " ,
"options" : {
"script" : " ./bin/example-script "
}
},
{
"id" : " cbs " ,
"strategy" : " cbs " ,
"name" : " CBS " ,
"credentialsNecessary" : true ,
"template" : " cbs:{id} " ,
"options" : {
"url" : " https://example.com/ext/api/colirich/users/info " ,
"apiKey" : " abcdef1234567890 "
}
}
] Untuk mengonfigurasi penyedia lokal, silakan gunakan skrip yang disediakan di bawah bin/manage-local.js . Ini akan memungkinkan Anda untuk membuat/menghapus penyedia lokal, dan membuat/menghapus pengguna untuk penyedia lokal.
Anda dapat menyesuaikan jalur ke file providers.json dengan PROVIDERS_PATH di .env .
Catatan tentang menggunakan penyedia MediaWiki:
"baseURL": "https://www.wikidata.org/" .https://coli-conc.gbv.de/login/login/wikidata/return untuk instance login-server kami).Catatan tentang menggunakan penyedia skrip:
lib/script-strategy.js ).options.script ) dapat relatif terhadap folder root server login, atau jalur absolut (disarankan untuk Docker).bin/example-script .chmod +x ).id yang ditetapkan ketika otentikasi berhasil. Secara opsional, name dapat disediakan dan akan digunakan sebagai nama tampilan.Login-Server menawarkan token web JSON yang dapat digunakan untuk mengotentikasi terhadap layanan lain (seperti jskos-server). JsonWebtoken digunakan untuk menandatangani token.
Secara default, keypair RSA baru dihasilkan ketika aplikasi pertama kali dimulai (2048 bit, menggunakan Node-RSA). Keypair yang dihasilkan ini secara default tersedia di ./private.key dan ./public.key . Anda dapat memberikan file ./public.key ke layanan lain yang perlu memverifikasi token. Atau, kunci publik yang saat ini digunakan ditawarkan di titik akhir /tentang.
Anda juga dapat memberikan jalur khusus untuk file kunci dengan mengatur JWT_PRIVATE_KEY_PATH dan JWT_PUBLIC_KEY_PATH di .env . Jika salah satu atau kedua kunci tidak dapat ditemukan, kunci akan dihasilkan. Secara default, algoritma RS256 digunakan, tetapi algoritma kunci publik lainnya dapat digunakan dengan mengatur JWT_ALGORITHM .
Secara default, setiap token berlaku selama 120 detik. Anda dapat menyesuaikan ini dengan mengatur JWT_EXPIRES_IN di .env .
Token dapat diterima baik melalui titik akhir /token atau dengan menggunakan permintaan WebSocket dari Type token . Selain itu, token dikirim melalui Websocket setelah pengguna masuk dan kemudian secara teratur sebelum token terakhir berakhir.
Contoh cara memverifikasi token:
import jwt from "jsonwebtoken"
// token, e.g. from user request
let token = "..."
// get public key from file or endpoint
let publicKey = "..."
jwt . verify ( token , publicKey , ( error , decoded ) => {
if ( error ) {
// handle error
// ...
} else {
let { user , iat , exp } = decoded
// user is the user object
// iat is the issued timestamp
// exp is the expiration timestamp
// ...
}
} )Atau, Anda dapat menggunakan paspor-jwt (contoh akan mengikuti).
Menampilkan halaman arahan dengan informasi umum tentang server login.
Menampilkan situs untuk mengelola akun pengguna seseorang (jika sudah diautentikasi) atau mengarahkan ke /login (jika tidak diautentikasi).
Menampilkan situs untuk mengelola sesi pengguna (jika diautentikasi) atau mengarahkan ke /login (jika tidak diautentikasi).
Menunjukkan situs untuk masuk (jika tidak diautentikasi) atau mengarahkan ke /account (jika diautentikasi).
Jika parameter kueri redirect_uri diberikan, situs akan mengarahkan kembali ke URI yang ditentukan setelah login yang berhasil. (Jika parameter diberikan, tetapi kosong, itu akan menggunakan pengirim sebagai URI.)
Menampilkan halaman login untuk penyedia. Untuk penyedia OAuth, halaman ini akan mengarahkan kembali ke halaman penyedia untuk menghubungkan identitas Anda, yang kemudian mengalihkan ke /login/:provider/return . Untuk penyedia menggunakan kredensial, ini akan menunjukkan formulir login.
Halaman ini juga menangani redirect_uri (lihat /login di atas).
Pasca titik akhir untuk penyedia menggunakan kredensial. Jika berhasil, itu akan mengalihkan ke /account , jika tidak, ia akan mengarahkan kembali ke /login/:provider .
Lepaskan penyedia dari pengguna dan mengarahkan ke /account .
Mencatat pengguna dari akun mereka. Perhatikan bahwa sesi akan tetap karena digunakan untuk websockets. Ini memungkinkan aplikasi untuk mengirim acara ke websockets aktif untuk sesi saat ini, bahkan jika pengguna telah keluar.
Menampilkan situs untuk menghapus akun pengguna seseorang.
Melakukan penghapusan akun pengguna dan mengarahkan ke /login .
Server menyediakan titik akhir pengalihan oAuth (pengalihan URI) untuk setiap penyedia oAuth.
Titik akhir panggilan balik untuk permintaan OAuth. Akan menyimpan identitas yang terhubung ke pengguna (atau membuat pengguna baru jika perlu) dan mengarahkan ke /account .
Sebelum pemrograman langsung terhadap HTTP API dan WebSocket API, lihatlah perpustakaan browser JavaScript Login-Client. Dapat dilihat beraksi di sini (sumber untuk situs itu).
Mengembalikan objek dengan title kunci (judul instance-server login), env (lingkungan, seperti development atau production ), publicKey (biasanya kunci publik RSA), dan algorithm (algoritma JSONWEBTOKen yang digunakan). Kunci pribadi yang sesuai untuk kunci publik yang diberikan digunakan saat menandatangani JWTS.
Mengembalikan daftar penyedia yang tersedia (dilucuti informasi sensitif).
Mengembalikan pengguna yang saat ini masuk. Mengembalikan kesalahan 404 saat tidak ada pengguna yang masuk.
Mengembalikan pengguna tertentu. Saat ini dibatasi untuk ID pengguna sendiri.
Menyesuaikan pengguna tertentu. Hanya dapat digunakan jika pengguna yang sama saat ini masuk. Properti yang diizinkan untuk berubah: name (yang lainnya akan diabaikan).
Menghapus semua sesi untuk pengguna saat ini, kecuali sesi saat ini.
Menghapus sesi dengan sessionID :id (harus menjadi sesi untuk pengguna saat ini).
Mengembalikan token web JSON dalam format:
{
"token" : " <JWT> " ,
"expiresIn" : 120
}Lihat juga: JWTS.
Token itu sendiri akan berisi properti user (yang berisi informasi tentang pengguna yang saat ini masuk, atau nol jika pengguna tidak masuk) dan properti sessionID yang diperlukan untuk mengotentikasi dalam koneksi WebSocket.
API Websocket di Base URL / mengirim acara tentang pengguna atau sesi saat ini. Acara dikirim sebagai string encoded JSON yang terlihat seperti ini:
{
"type" : " event name (see below) " ,
"date" : " date (as ISOString) " ,
"data" : {
"user" : {
"uri" : " URI of user " ,
"name" : " name of user " ,
"identities" : {
"xzy" : {
"id" : " ID of user for provider xzy " ,
"uri" : " URI or profile URL of user for provider xzy " ,
"name" : " display name of user for provider xzy (if available) " ,
"username" : " username of user for provider xzy (if available) "
}
}
}
}
}open - Dikirim setelah koneksi Websocket dibuat, gunakan ini alih -alih ws.onopen !loggedIn - Dikirim saat pengguna telah masuk (akan dikirim segera setelah membuat WebSocket jika pengguna sudah masuk)loggedOut - Dikirim saat pengguna telah keluar (akan dikirim segera setelah membuat WebSocket jika pengguna tidak masuk)updated - Dikirim saat pengguna diperbarui (misalnya menambahkan identitas baru, dll.)providers - Dikirim setelah Websocket Connection didirikan (terdiri dari data.providers properti. PENDIRIMAN dengan daftar penyedia yang tersedia)about - Dikirim setelah koneksi WebSocket dibuat ( data properti akan memiliki format yang sama seperti di Get /About)token - Dikirim ketika pengguna telah masuk dan kemudian dalam interval sebelum token sebelumnya kedaluwarsa ( data properti akan memiliki format yang sama seperti di GET /Token)authenticated - Dikirim sebagai balasan sukses saat meminta otentikasi (lihat di bawah)pong - Dikirim sebagai jawaban atas permintaan jenis ping (dapat digunakan untuk menentukan apakah Websocket telah menjadi basi)sessionAboutToExpire - Dikirim ketika sesi yang saat ini terkait akan kedaluwarsaerror - Dikirim sebagai Jawaban ke Pesan Malformed melalui WebSocket (terdiri dari data.message properti.Anda juga dapat mengirim permintaan ke Websocket. Ini juga harus menjadi string yang dikodekan JSON dalam bentuk berikut:
{
"type" : " name of request "
} Ini adalah permintaan khusus yang menggunakan JWT yang diperoleh dari GET /Token untuk mengaitkan Websocket saat ini dengan sesi tertentu (terkirim objek permintaan membutuhkan token properti)
Permintaan authenticate kadang-kadang diperlukan ketika WebSocket digunakan dari domain yang berbeda dari server login. Dalam hal ini, token perlu diminta melalui API (misalnya menggunakan fetch dengan credentials: "include" atau Axios dengan opsi withCredentials: true ) dan dikirim melalui WebSocket. Token mencakup sessionID terenkripsi yang kemudian akan dikaitkan dengan koneksi WebSocket. Berikut adalah contoh tentang bagaimana alur kerja dari aplikasi web bisa terlihat seperti: https://coli-conc.gbv.de/login/api
Berikut ini adalah contoh sederhana tentang cara terhubung ke Websocket.
// Assumes server is run on localhost:3005
let socket = new WebSocket ( "ws://localhost:3005" )
socket . addEventListener ( "message" , ( message ) => {
try {
let event = JSON . parse ( message )
alert ( event . event , event . user && event . user . uri )
} catch ( error ) {
console . warn ( "Error parsing WebSocket message" , message )
}
} ) PRS diterima.
dev sebagai dasar. Perubahan dari dev akan digabungkan menjadi master hanya untuk rilis baru.Hanya untuk pengelola
Harap bekerja di cabang dev selama pengembangan (atau lebih baik lagi, kembangkan di cabang fitur dan gabungkan menjadi dev saat siap).
Ketika rilis baru siap (yaitu fitur selesai, digabungkan menjadi dev , dan semua tes berhasil), jalankan skrip rilis yang disertakan (ganti "patch" dengan "minor" atau "mayor" jika perlu):
npm run release:patchIni akan:
devdev terbarunpm version patch (atau "Minor"/"Mayor")devmasterdevmaster dengan tagdevSetelah menjalankan ini, tindakan GitHub akan secara otomatis membuat draf rilis GitHub baru. Silakan edit dan publikasikan rilis secara manual.
MIT © 2019 Verbundzentrale des GBV (VZG)