@it-enterprise/jwtauthentication
Version:
JSON Web Token-Based authentication library
365 lines (331 loc) • 16.4 kB
Markdown
# @it-enterprise/jwtauthentication
@it-enterprise/jwtauthentication - это клиенская библиотека для работы с аутентификацией и авторизацией по схеме Token-Based Authentication с использованием стандарта JSON Web Tokens.
>Токены предоставляют собой средство авторизации для каждого запроса от клиента к серверу.
Токены генерируются на сервере основываясь на секретном ключе, который хранится на сервере.
Токен хранится на клиенте и используется при необходимости авторизации како-го либо запроса.
### JSON Web Tokens!
JSON Web Token (JWT) — содержит три блока, разделенных точками: заголовок(header), набор полей (payload) и сигнатуру. Первые два блока представлены в JSON-формате и дополнительно закодированы в формат base64. Набор полей содержит произвольные пары имя/значения, притом стандарт JWT определяет несколько зарезервированных имен (iss, aud, exp и другие).
**Принцип работы:**
Для авторизации используется логин/пароль и fingerprint.
>Что такое **fingerprint**? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это сгенерированный хеш на базе неких уникальных параметров/компонентов браузера. Преимущество fingerprint'a в том, что он нигде персистентно не хранится и генерируется только в момент логина и обновления токена.
**...таким образом:**
- Пользователь логинится в приложении, передавая логин/пароль и fingerprint
- Сервер проверят подлинность логина/пароля
- В случае удачи создает и записывает сессию в БД
- Отправляет клиенту два токена **access** и **refresh token** (uuid взятый из выше созданной сессии)
`accessToken": "eyJhbGciOiJIUzI1NiIs...",`
`refreshToken": "9f34dd3a-ff8d-43aa-b286-9f22555319f6`
- Библиотека сохраняет токены, используя **access token** для последующей авторизации запросов.
**access token** - используется для авторизации запросов и хранения информации о пользователе.
**refresh token** - выдается сервером по результам успешной аутентификации и используется для получения новой пары access/refresh токенов.
Каждый токен имеет свой срок жизни, `access`: 30 мин, `refresh`: 60 дней
Перед каждым запросом библиотека предварительно проверяет время жизни access token'а и если оно истекло использует refresh token чтобы обновить ОБА токена и продолжает использовать новый access token.
### Установка
```sh
npm install @it-enterprise/jwtauthentication
```
### Подключение
Для использования библиотеки ее необходимо импортировать в главном файле приложения (например `main.js`).
```js
// main.js
import auth from '@it-enterprise/jwtauthentication'
```
### Конфигурирование
Настройка конфигурации предполагает передачу объекта с опциями в метод `config`.
Опции включают в себя три параметра:
-`baseUrl` (обязательный) - абсолютный или относительний путь к GraphQlServer.
```js
// main.js
auth.config({ baseUrl: 'https://m.it.ua/GraphQlServer/'})
auth.config({ baseUrl: 'http://localhost:5002'})
```
если базовый URL относительный, адрес хоста будет взят из `window.location.origin`
```js
// В данном примере при запуске на локальной машине получим http://localhost:8080/ForceBPM/GraphQlServer/
auth.config({ baseUrl: 'ForceBPM/GraphQlServer'})
```
-`onError` (не обязательный) - функция-обработчик ошибок, принимает на вход объект ошибки `error`.
Если передана, вызывается в случае возникновения ошибок в запросах к серверу аутентификации.
```js
// main.js
auth.config({
baseUrl: window.myConfig.GrapgQlUrl,
onError: e => {
e.response && e.response.status === 400
? store.dispatch('auth/logout')
: console.log(e)
}
})
```
-`onBeforeRefresh` (не обязательный) - функция вызываемая перед каждым запросом на обновление токена.
На вход принимает `refreshToken` и `fingerprint` с которыми отправляется запрос.
```js
// main.js
auth.config({
baseUrl: 'https://m.it.ua/GraphQlServer/',
onBeforeRefresh: (refreshToken, fingerprint) => {
console.error('refreshToken:', refreshToken, 'fingerprint:', fingerprint)
}
})
```
### API
##### getAllowedAuthTypes (async)
Запрашивает доступные способы входа в систему и возвращает Promise c объектом результата:
```js
auth.getAllowedAuthTypes()
// return
{
AllowedAuthTypes: 'Sms,Email,Google,Facebook,SmartId,DigitalCertificate'
}
```
##### Login (async)
Реализует стандартный способ входа с использованием логина и пароля и возвращает Promise c объектом результата:
```js
auth.login('login', 'password', rememberMe)
// return
{
success: true/false,
errorMessage: ''
}
```
##### LoginByCode (async)
Реализует способ входа с использованием QR-code и возвращает Promise c объектом результата:
```js
auth.loginByCode('code')
// return
{
success: true/false,
errorMessage: ''
}
```
##### GetDelegatedUsers (async)
Запрашивает делегированные пользователю права и возвращает Promise c массивом делегированных прав либо `null` в случае неудачи:
```js
auth.getDelegatedUsers('userId')
// return
delegatedUsers: [
{
USERID: 'userId',
USERNAME: 'userName',
IsActive: true/false
}
]
```
##### GetDelegatedRights (async)
Запрашивает права делегированные другим пользователям и возвращает Promise c массивом делегированных прав либо `null` в случае неудачи:
```js
auth.getDelegatedRights()
// return
delegatedRights: [
{
ID: 'Id', // уникальный идентификатор
USERID: 'userId', // ID пользователя
FIO: 'fio', // ФИО пользователя
USERIDSUB: 'userIdSub', // ID заместителя
FIOSUB: 'fioSub', // ФИО заместителя
DATEFROM: 'dateFrom', // дата с
DATETO: 'dateTo', // дата по
PR_DO: 'prDo', // отменено
COMM: 'comm' // примечание
}
]
```
##### ApplyDelegatedRights (async)
Применяет делегированные права другого пользователя и возвращает Promise c объектом результата:
```js
auth.applyDelegatedRights('userId')
// return
{
success: true/false,
errorMessage: ''
}
```
##### AddDelegateUser (async)
Делегирует права другому пользователю и возвращает Promise c объектом результата.
В качестве параметров принимает ID пользователя, которому делегируются права,
а также даты начала и окончания действия делегирования в формате 'YYYY-MM-DD HH:mm':
```js
auth.addDelegateUser('userId', 'dateFrom', 'dateTo')
// return
{
success: true/false,
errorMessage: ''
}
```
##### editDelegation (async)
Редактирует либо удаляет права делегированные другому пользователю и возвращает Promise c объектом результата.
В качестве параметров принимает сериализованный объект с набором параметров:
- MODE - режим (EDIT - корректировка, DELETE - удаление)
- ID - уникальный идентификатор - обязательно для всех режимов
- DATEFROM, DATETO, PR_DO, COMM - - поля для корректировки
```js
auth.editDelegation(params)
// return
{
success: true/false,
errorMessage: ''
}
```
##### GetToken (async)
Возвращает валидный `accessToken` либо `undefined` если токен отсутсвует.
```js
auth.getToken()
```
Используется для проверки наличия токена при переходе на защищенный роут,
а так же для добавления токена к запросам в виде хедера. Например:
```js
const token = await auth.getToken()
headers: {
'Authorization': `Bearer ${token}`
}
```
##### GetUserData
Парсит `accesToken` и возвращает информацию о пользователе в виде объекта, либо `null` в случае отсутствия токена:
```js
auth.getUserData()
// return
{
id: 'userId',
login: 'userLogin',
userName: 'userName',
userPhoto: 'http(s)://linkToUserPhoto',
otherServiceFilds: 'exp', 'iat', 'nbf'...
}
```
##### ClearTokens
Удаляет токены из всех хранилищ.
Используется при выходе из приложения или переходе на страницу логина.:
```js
auth.clearTokens()
```
##### ConfirmCode
Подтерждает временный пароль для 2ФА, в случае истечении времени или не коректности возвращает описание ошибки.:
```js
auth.confirmCode('confirmCode')
// return
{
success: true/false,
errorMessage: ''
}
```
##### GetAuthGuid
Получить GUID для аутентификации цифровой подписи.:
```js
auth.getAuthGuid()
// return
{
GUID: ''
}
```
##### LoginByDigitalSignature
Авторизоваться с помощью цифровая подпись.:
```js
auth.loginByDigitalSignature('sign')
// return
{
success: true/false,
errorMessage: ''
}
```
##### LoginByOidc
Авторизоваться с помощью цифровая подпись.:
```js
auth.loginByOidc('options')
// options
{
prompt: '', //НЕОБЯЗАТЕЛЬНЫЙ. Разделенный пробелами и чувствительный к регистру список строковых значений ASCII, который указывает, будет ли сервер авторизации запрашивать у конечного пользователя повторную аутентификацию и согласие.
returnUrl: '', //НЕОБЯЗАТЕЛЬНЫЙ. URI перенаправления, на который будет отправлен ответ.
lang: '', //НЕОБЯЗАТЕЛЬНЫЙ. Предпочитаемые конечным пользователем языки и скрипты для пользовательского интерфейса, представленные в виде разделенного пробелами списка значений языковых тегов BCP47 [RFC5646], упорядоченных по предпочтениям.
acr_values: '' //НЕОБЯЗАТЕЛЬНЫЙ. Запрошенные значения ссылки на класс контекста аутентификации.
}
// return
{
success: true/false,
errorMessage: ''
}
```
##### LoginByOidcRedirectComplite
Сохранить токен в sessionStorage.:
```js
auth.loginByOidcRedirectComplite('token')
```
##### LoginBySMS
Авторизоваться с помощью телефона.:
```js
auth.loginBySMS('phone')
// return
{
success: true/false,
errorMessage: ''
}
```
##### EnterOneTimeSMSPassword
Авторизоваться с помощью одноразового пароля.:
```js
auth.enterOneTimeSMSPassword('tmpPass')
// return
{
success: true/false,
errorMessage: ''
}
```
##### LoginByPINCode
Авторизоваться с помощью PIN-кода.:
```js
auth.loginByPINCode('code')
// return
{
success: true/false,
errorMessage: ''
}
```
##### LoginByBarCode
Авторизоваться с помощью штрих-кода.:
```js
auth.loginByBarCode('code')
// return
{
success: true/false,
errorMessage: ''
}
```
##### Logout
Авторизоваться с помощью одноразового пароля.:
```js
auth.logout('options')
// options
{
returnUrl: '' //НЕОБЯЗАТЕЛЬНЫЙ. URI перенаправления, на который будет отправлен ответ.
}
// return
{
success: true/false,
errorMessage: ''
}
```
##### AddDelegateUser
Авторизоваться с помощью одноразового пароля.:
```js
auth.addDelegateUser('params')
// params
{
returnUrl: ''
}
// return
{
success: true/false,
errorMessage: ''
}
```
### Рекомендации
- В первую очередь убидетесь, что базовий путь к GraphQlServer корректный и передан в виде строки.
- Для обработки результатов асинхронных методов используйте конструкцию async/await или .then()/.catch()
- Все открытые методы библиотеки обрабатывают ошибки и выводят соответсвующие сообщения в консоль.
- Если сервер вернул ошибку во время запроса она также будет отображена перед сервисным сообщением.
- При работе с серверным API, необходимо перехватывать ошибки `statusCode = 401 (unauthorized)`
для перенаправления пользователя на страницу логина.
- Если в приложении используются делегированные права можно запрашивать их при получении данных пользователя и объеденять на уровне клиентского приложения. Например:
```js
const user = auth.getUserData()
user.delegatedRights = await auth.getDelegatedRights(user.id) || []
```