Этот репозиторий предлагает сервер входа для использования с инструментом картирования Cocoda. Это позволяет пользователям аутентифицировать использование различных поставщиков (например, github, orcid). См. Https://coli-conc.gbv.de/login/api для примера того, как вы можете использовать это.
.envproviders.jsonapplications.jsonЛогин-сервер требует node.js (> = v18, v20, рекомендуется) и доступ к базе данных MongoDB (> = V5, рекомендуется v7).
git clone https://github.com/gbv/login-server.git
cd login-server
npm install
# after setting up or changing providers, create indexes
npm run indexesЛогин-сервер также доступен через Docker. Пожалуйста, обратитесь к документации по адресу https://github.com/gbv/login-server/blob/master/docker/readme.md для получения более подробной информации.
Если запустить сервер за обратным прокси, обязательно включите заголовок X-Forwarded-Proto , разрешите все методы HTTP и включите прокси-прокси WebSocket.
Вам нужно предоставить два файла конфигурации:
.envДля настройки приложения:
# 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.jsonЧтобы настроить поставщиков. Смотрите поставщиков.
applications.json Чтобы предоставить пользователю информацию о том, какие приложения получают доступ к своим данным, и какое приложение инициировало вход в сеанс, вы можете предоставить список приложений в applications.json . Список должен быть массивом объектов, и каждая объекты должны иметь url и name . Пример:
[
{
"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 должен быть доступен, потому что интерфейс будет ссылаться на него. Сеанс связан с приложением, если его URL -адрес ссылки содержит url приложения. Приложения будут проверены сверху вниз, поэтому вы должны заказать его от наиболее конкретного URL на наименее конкретный URL (см. Пример выше).
npm run startСервер предоставляет веб -интерфейс, HTTP API и WebSocket.
Веб -интерфейс позволяет пользователям создавать и управлять учетными записями с подключениями к нескольким идентификаторам у поставщиков идентификаторов (см. Поставщики). Поставщики используются для аутентификации пользователей, потому что сервер входа не хранит никаких паролей (единый вход).
HTTP API и WebSocket позволяют клиентским приложениям взаимодействовать с сервером входа в систему, например, проверить, был ли пользователь вошел в систему, и выяснить, какие идентификаторы принадлежат пользователю (см. Login-Client и Login-Client-Vue для библиотек JavaScript для подключения веб-приложений с помощью входа в систему).
Сервер входа в систему может быть дополнительно использоваться для аутентификации пользователей по сравнению с другими службами, чтобы пользователи могли подтвердить свои личности.
bin Directory содержит вспомогательный скрипт для администрирования экземпляра сервера, такого как перечисление учетных записей пользователей и управление локальными поставщиками.
Тесты используют тот же MongoDB, что и в .env , только с постфикс -test после имени базы данных.
npm test Login-Server использует паспорт (GitHub) в качестве промежуточного программного обеспечения для аутентификации. Паспорт использует так называемые «стратегии» для поддержки аутентификации с различными поставщиками. Здесь можно найти список доступных стратегий. В настоящее время поддерживаемые стратегии в логин-сервере:
Поскольку стратегии используют разные параметры в своих обратных вызовах, каждая стратегия имеет свой собственный файл обертки в strategies/ . Чтобы добавить еще одну стратегию для входа в систему, добавьте файл с именем {name}.js (где {name} -это имя стратегии, которая используется с passport.authenticate ) со следующей структурой (GitHub как пример):
/**
* 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 )
} )Вы можете рассмотреть существующие стратегии в качестве примеров и добавить свои собственные с помощью запроса на притяжение.
После того, как вы добавили стратегию, вы можете использовать ее, добавив поставщика к 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 "
}
]Каждый объект в списке поставщиков может иметь следующие свойства:
id (требуется) - уникальный идентификатор для поставщика.strategy (требуется) - Имя стратегии паспорта, используемой поставщиком.name (требуется) - отображение имени провайдера.template (необязательно) - строка шаблона для генерации URI (заполнитель {field} может быть любым полем, предоставленным в объекте providerProfile , обычно {id} или {username} ).credentialsNecessary (необязательно) - установить на true , если для этого поставщика необходимы учетные данные имени пользователя и пароля. Вместо перенаправления (для OAuth) Login-Server покажет форму входа в систему, которая отправит учетные данные в конечную точку после.options (в основном требуются) - объект опций для стратегии, часто содержащий учетные данные клиента для конечной точки аутентификации.image (необязательно) - изображение, связанное с поставщиком. Будет отображаться на странице входа в систему и в списке подключенных идентификаторов. Вы можете предоставить статические изображения в static/ . Значение для имущества будет тогда static/myimage.svg . Если имя файла соответствует id поставщика, изображение будет автоматически связано.url (необязательно) - URL для поставщика; будет связан на его изображении /значке в /account . Есть URL -адреса по умолчанию для стратегий github , orcid , mediawiki и stackexchange . Ниже приведены примеры providers.json .
[
{
"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 "
}
}
] Чтобы настроить локальных поставщиков, используйте предоставленный скрипт в рамках bin/manage-local.js . Это позволит вам создавать/удалять локальных провайдеров и создавать/удалять пользователей для местных провайдеров.
Вы можете настроить путь к файлу providers.json с помощью PROVIDERS_PATH в .env .
Примечания об использовании поставщика MediaWiki:
"baseURL": "https://www.wikidata.org/" .https://coli-conc.gbv.de/login/login/wikidata/return для нашего экземпляра для входа в систему).Примечания об использовании поставщика сценариев:
lib/script-strategy.js ).options.script ) может быть относительно корневой папки сервера входа, либо абсолютным путем (рекомендуется для Docker).bin/example-script .chmod +x ).id , когда аутентификация была успешной. Необязательно, name может быть предоставлено и будет использоваться в качестве имени отображения.Login-Server предлагает JSON Web токены, которые можно использовать для аутентификации против других услуг (например, JSKOS-Server). JsonWebtoken используется для подписания токенов.
По умолчанию новый клавиатура RSA генерируется, когда приложение впервые запускается (2048 бит, с использованием Node-RSA). Эта сгенерированная клавиатура по умолчанию будет доступна в ./private.key и ./public.key . Вы можете дать файл ./public.key любому другую службу, которая должна проверить токены. В качестве альтернативы, в настоящее время используемый открытый ключ предлагается в конечной точке.
Вы также можете предоставить пользовательский путь для файлов ключей, установив JWT_PRIVATE_KEY_PATH и JWT_PUBLIC_KEY_PATH в .env . Если один или оба ключи не могут быть найдены, ключи будут сгенерированы. По умолчанию алгоритм RS256 используется, но любой другой алгоритм открытых ключей может быть использован путем установки JWT_ALGORITHM .
По умолчанию каждый токен действителен в течение 120 секунд. Вы можете настроить это, установив JWT_EXPIRES_IN в .env .
Токены получаются либо через конечную точку /токена, либо с помощью запроса WebSocket of Type token . Кроме того, токен отправляется через WebSocket после того, как пользователь входит в систему, а затем регулярно до истечения последнего токена.
Пример, как проверить токен:
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
// ...
}
} )В качестве альтернативы, вы можете использовать Passport-JWT (пример будет следовать).
Показывает целевую страницу с общей информацией о сервере входа в систему.
Показывает сайт для управления учетной записью пользователя (если уже аутентифицирована) или перенаправления в /login (если не аутентифицирована).
Показывает сайт для управления сеансами пользователя (если аутентифицирован) или перенаправления в /login (если не аутентифицировано).
Показывает сайт для входа (если не аутентифицирована) или направляет /account (если аутентифицирует).
Если приведен параметр запроса redirect_uri , сайт будет перенаправлен на указанный URI после успешного входа. (Если параметр дан, но пуст, он будет использовать реферателя в качестве URI.)
Показывает страницу входа для поставщика. Для поставщиков OAuth эта страница будет перенаправлена на страницу провайдера, чтобы подключить вашу личность, которая затем перенаправляет /login/:provider/return . Для поставщиков, использующих учетные данные, это покажет форму входа в систему.
Эта страница также обрабатывает redirect_uri (см. /login выше).
Пост конечной точки для поставщиков, использующих учетные данные. В случае успеха он будет перенаправлен на /account , в противном случае он будет перенаправить обратно в /login/:provider .
Отсоединяет поставщика от пользователя и перенаправляет в /account .
Выбивает пользователя из своей учетной записи. Обратите внимание, что сеанс останется, потому что он используется для веб -копейков. Это позволяет приложению отправлять события в Active WebSockets для текущего сеанса, даже если пользователь вышел из системы.
Показывает сайт для удаления учетной записи пользователя.
Commits удаление учетной записи пользователя и перенаправление в /login .
Сервер предоставляет конечную точку перенаправления OAuth (перенаправление URI) для каждого поставщика OAuth.
Конечная точка обратного вызова для запросов OAuth. Сохранит подключенную идентификацию для пользователя (или при необходимости создаст нового пользователя) и перенаправить в /account .
Перед непосредственным программированием против HTTP API и API WebSocket посмотрите на библиотеку браузера JavaScript Login-Client. Это можно увидеть в действии здесь (источник для этого сайта).
Возвращает объект с title Keys (название экземпляра логин-сервера), env (окружающая среда, такая как development или production ), publicKey (обычно публичный ключ RSA) и algorithm (используемый алгоритм JSonWebtoken). Соответствующий закрытый ключ к данному открытому ключу используется при подписании JWT.
Возвращает список доступных поставщиков (лишенная конфиденциальная информация).
Возвращает в настоящее время зарегистрированный пользователя. Возвращает ошибку 404, когда пользователь не вошел в систему.
Возвращает конкретного пользователя. В настоящее время ограничено собственным идентификатором пользователя.
Настраивает конкретного пользователя. Может использоваться только в том случае, если в настоящее время входит в систему одного пользователя. Допустимые свойства для изменения: name (все остальное будет игнорировано).
Удаляет все сеансы для текущего пользователя, кроме текущего сеанса.
Удаляет сеанс с SessionId :id (необходимо быть сеансом для текущего пользователя).
Возвращает веб -токен JSON в формате:
{
"token" : " <JWT> " ,
"expiresIn" : 120
}Смотрите также: JWTS.
Сам токен будет содержать свойство user (которое либо содержит информацию о в данный момент, зарегистрированным в пользователе, либо является NULL, если пользователь не вошел в систему) и о свойстве sessionID , которое необходимо для аутентификации в рамках подключения к веб -зоне.
API WebSocket на базовом URL / отправляет события о текущем пользователе или сеансе. События отправляются как кодируемые JSON струны, которые выглядят так:
{
"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 - отправлено после установки соединения WebSocket, используйте это вместо ws.onopen !loggedIn - отправлено, когда пользователь вошел в систему (будет отправлен сразу после создания WebSocket, если пользователь уже вошел в систему)loggedOut - отправлено, когда пользователь вышел в систему (будет отправлен сразу после создания WebSocket, если пользователь не вошел в систему)updated - отправлено, когда пользователь был обновлен (например, добавил новую личность и т. Д.)providers - отправлено после установки подключения к WebSocket (состоит из data.providers имущества. Провидеры со списком доступных поставщиков)about - отправлено после установки подключения к WebSocket ( data о свойствах будут иметь тот же формат, что и в GET /About)token - отправлено, когда пользователь вошел в систему, а затем через интервалы до истечения срока действия предыдущего токена ( data о свойствах будут иметь тот же формат, что и в Get /Token)authenticated - отправлено в качестве успешного ответа при запросе аутентификации (см. Ниже)pong - отправлено в качестве ответа на запрос типа ping (можно использовать для определения того, стал ли WebSocket устареть)sessionAboutToExpire - отправлено, когда истекает в настоящее время связанный сессияerror - отправлена в качестве ответа на утронутое сообщение через WebSocket (состоит из свойства data.message с сообщением об ошибке)Вы также можете отправить запросы в WebSocket. Это также должны быть кодируемыми JSON строками в следующей форме:
{
"type" : " name of request "
} Это специальный запрос, который использует JWT, приобретенную от Get /Token, чтобы связать текущий WebSocket с конкретным сеансом (отправленный объект запроса нуждается в token ).
Запрос authenticate иногда необходим, когда WebSocket используется из другого домена, чем логин-сервер. В этом случае токен необходимо запрашивать через API (например, с использованием credentials: "include" или Axios с опцией withCredentials: true ) и отправлять через WebSocket. Токен включает в себя зашифрованный SessionID, который затем будет связан с соединением WebSocket. Вот пример того, как может выглядеть рабочий процесс из веб-приложения: https://coli-conc.gbv.de/login/api
Ниже приведен простой пример того, как подключиться к 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 принят.
dev в качестве основы. Изменения от dev будут объединены в master только для новых выпусков.Только для сопровождающих
Пожалуйста, поработайте над dev Branch во время разработки (или, что еще лучше, разрабатывайте в филиале функции и слияйте в dev , когда готовы).
Когда новый релиз готов (т.е. функции завершены, объединены в dev , и все тесты достигают успеха), запустите сценарий включенного выпуска (замените «патч» на «несовершеннолетний» или «майор», если это необходимо):
npm run release:patchЭто будет:
devdev вновь современенnpm version patch (или «несовершеннолетний»/«майор»)devmasterdevmaster с тегамиdevПосле запуска действия Github Actions автоматически создаст новый проект выпуска GitHub. Пожалуйста, отредактируйте и опубликуйте релиз вручную.
MIT © 2019 VERBUNDZENTRALE DES GBV (VZG)