Примечание редактора: я считаю, что аутентификация должна быть одной из основных функций, которые должны быть у большинства веб-сервисов. Существует множество способов реализации проверки авторизации, среди которых JSON Web Token (JWT), который использует проверку токена, пользуется популярностью у все большего числа разработчиков. По сравнению с традиционным методом проверки он будет более безопасным, и, условно говоря, поскольку зашифрованная строка содержит информацию о разрешениях, не требуется дополнительный запрос к базе данных. Сегодня мы пригласили Лу Шицзе, разработчика ThinkJS, объяснить нам, как использовать службу проверки разрешений JWT при загрузке ThinkJS.
JSON Web Token (JWT) — очень легкийТехнические характеристики. Эта спецификация позволяет нам использовать JWT для безопасной и надежной передачи информации между пользователем и сервером. Он предоставляет токен на основе формата JSON для аутентификации безопасности.
Состав JWT
JWT состоит из трех частей, а именно заголовка (header), полезной нагрузки (load) и подписи (visa), которые соединены десятичными точками.
В этом примере файл cookie с именем jwt-token используется для хранения JWT, например:
jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0.WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8;
в:
часть | ценность |
---|---|
header | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 |
payload | eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0 |
signature | WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8 |
header
Заголовок получается после base64Encode типа и алгоритма хеширования. Base64Decode заголовок в шкале, чтобы получить:
{
"alg":"HS256”,
"typ":”JWT"
}
payload
Полезная нагрузка получается после base64Encoding информации, которую нам нужно передать. Base64Decode полезной нагрузки в этом примере, чтобы получить:
{
"name":"lushijie”,
"iat":1532595255, // JWT 发布的时间
"exp”:1532595270 // JWT 过期的时间,15秒后过期
}
В этом примере iat и exp являются полями по умолчанию в koa-jwt. Кроме того, необязательные объявления, зарегистрированные в стандарте JWT, включают jti, iss и т. д. Заинтересованные партнеры могут ознакомиться с другими связанными стандартами. Поскольку полезная нагрузка может быть декодирована на стороне клиента, не рекомендуется хранить в полезной нагрузке конфиденциальную информацию, например пароль пользователя.
signature
подпись включает заголовок, полезную нагрузку и ключ, формула расчета выглядит следующим образом:
const encodedString = base64Encode(header) + "." + base64Encode(payload);
let signature = HMACSHA256(encodedString, '密钥');
Ключ здесь хранится на сервере, и клиент его не знает.
JWT-проверка
Кроме того, относительно просто проверить, является ли JWT действительным.Сервер вычисляет подпись в соответствии с методом расчета, описанным выше, и сравнивает ее с частью подписи проверяемого JWT.Если часть подписи равна, это действующий JWT.
Практика JWT в ThinkJS
Ниже мы реализуем в ThinkJS использование JWT для реализации интерфейса, доступ к которому возможен только после входа в систему. ThinkJS совместим со всеми промежуточными программами koa2, поэтому найдите готовый плагин jwt, здесь мы используем плагин koa-jwt. Кода koa-jwt всего несколько строчек, его можно немного прочитать, он прост для понимания, а потом начинаем им пользоваться~ Для начала нам нужно настроить koa-jwt в ThinkJS:
общедоступная конфигурация
/src/config/config.js:
module.exports = {
// ...
jwt: {
secret: 'lushijie-password',
cookie: 'jwt-token',
expire: 30 // 秒
},
}
Поскольку эти три параметра используются в разных местах, мы вынесли их в публичный конфиг для унифицированного управления.
Конфигурация промежуточного ПО
/src/config/middleware.js
const jwt = require('koa-jwt');
const isDev = think.env === 'development';
module.exports = [
// ...
{
handle: jwt,
// match(ctx) {
// return !/^\/index\/login/.test(ctx.path);
// },
options: {
cookie: think.config('jwt')['cookie'],
secret: think.config('jwt')['secret'],
passthrough: true
}
},
// payload 这里配置因为本例中 jwt 并没有用到 request 解析后的参数
];
Сначала я хотел определить, требует ли URL-адрес аутентификации при входе, настроив параметр match. Позже я обнаружил, что настраивать множество обычных правил очень проблематично. Во-вторых, koa-jwt не предоставляет хук для доступа к пользовательским ошибкам. , поэтому я отказался от схемы матча. .
Здесь используется конфигурация, предоставляемая koa-jwt.passthrough: true
, этот параметр позволяет нам продолжать выполнение следующего промежуточного ПО независимо от того, пройдена ли проверка разрешения или нет, но полезная нагрузка устанавливается на текущий ctx.
Наша обработка ошибок должна выполняться на логическом уровне, а не на уровне контроллера, иначе возникнут следующие проблемы: информацию об ошибке проверки, а затем сообщить об этом Нет доступа, что явно не соответствует требованиям.
Расширение think.Controller
Здесь мы расширяем think.Controller, здесь мы не расширяем think.Logic, потому что think.Logic наследуется от think.Controller.
/src/extend/controller.js
const jsonwebtoken = require('jsonwebtoken');
module.exports = {
authFail() {
return this.fail('JWT 验证失败');
},
checkAuth(target, name, descriptor) {
const action = descriptor.value;
descriptor.value = function() {
console.log(this.ctx.state.user);
const userName = this.ctx.state.user && this.ctx.state.user.name;
if (!userName) {
return this.authFail();
}
this.updateAuth(userName);
return action.apply(this, arguments);
}
return descriptor;
},
updateAuth(userName) {
const userInfo = {
name: userName
};
const {secret, cookie, expire} = this.config('jwt');
const token = jsonwebtoken.sign(userInfo, secret, {expiresIn: expire});
this.cookie(cookie, token);
return token;
}
}
Среди них authFail — операция сбоя проверки JWT, updateAuth — обновление JWT, здесь jsonwebtoken используется для генерации JWT и установки куки, checkAuth реализован с помощью метода декоратора, конечно, можно использовать и метод тебе нравится.
Здесь сгенерированный JWT записывается в cookie.Его можно сохранить и другими способами.koa-jwt предоставляет getToken, чтобы мы могли свободно получить JWT, подробно описывать который здесь не будем.
бизнес-логика контроллера
/src/controller/jwt1.js
const userList = {
lushijie: '123123',
xiaoming: '456456'
};
module.exports = class extends think.Controller {
async userAction() {
const userInfo = this.ctx.state.user;
if (userInfo) {
return this.success(userInfo);
} else {
return this.fail('获取用户信息失败');
}
}
loginAction() {
const {name, password} = this.get();
if (userList[name] && password === userList[name]) {
const token = this.updateAuth(name);
return this.success(token);
} else {
return this.fail('登录失败');
}
}
logoutAction() {
this.updateAuth(null);
return this.success('退出登录成功');
}
}
Простой контроллер jwt1 включает в себя три простые функции: вход в систему, выход из системы и получение информации о пользователе, среди которых получение информации о пользователе требует, чтобы вы вошли в систему, прежде чем вы сможете получить к ней доступ. Логин здесь — простая симуляция, аутентификация пользователя в реальном проекте будет сложнее, и принцип тот же.
Логическая проверка разрешений
/src/logic/jwt1.js
const {checkAuth} = think.Controller.prototype;
module.exports = class extends think.Logic {
@checkAuth
userAction(){
// 正常的参数验证逻辑
}
}
Такая проверка завершена! Если нужно проверить все действия в логике, просто добавьте декоратор в __before и не нужно добавлять другие действия!