Аутентификация на основе токенов недавно была изучена и интегрирована в отдельные проекты. В настоящее время методы аутентификации многих веб-сайтов перешли от традиционных файлов cookie + seesion к проверке токенов. По сравнению с традиционными методами проверки токены обладают лучшей масштабируемостью и безопасностью.
Традиционная аутентификация сеанса + cookie
Поскольку HTTP не имеет состояния, он не записывает личность пользователя. После того, как пользователь отправит учетную запись и пароль на сервер, фон проходит проверку, но статус не записывается, поэтому следующий запрос пользователя все равно требует проверки личности. Чтобы решить эту проблему, на стороне сервера необходимо сгенерировать запись, содержащую личность пользователя, то есть сессию, а затем эту запись отправить пользователю и сохранить локально, то есть файл cookie. Далее запрос пользователя принесет эту куку, если кука клиента может соответствовать сеансу сервера, значит, аутентификация пользователя прошла.
проверка личности токена
Процесс примерно такой:
- По первому запросу пользователь отправляет номер счета и пароль
- Если фоновая проверка пройдена, будет сгенерирован чувствительный ко времени токен, а затем токен будет отправлен пользователю.
- После того, как пользователь получает токен, он сохраняется локально, как правило, в локальном хранилище или файле cookie.
- Каждый последующий запрос будет добавлять этот токен в заголовок запроса, и все интерфейсы, которые должны подтвердить личность, будут проверены токеном.Если данные, проанализированные токеном, содержат информацию об идентификации пользователя, аутентификация пройдена.
По сравнению с традиционными методами проверки, проверка токена имеет следующие преимущества:
- При аутентификации на основе токенов токен передается через заголовок запроса, а не сохраняет информацию об аутентификации в сеансе или файле cookie. Это означает без гражданства. Вы можете отправлять запросы на сервер с любого терминала, который может отправлять HTTP-запросы.
- Может избежать CSRF-атак
- Когда сеанс читается, записывается или удаляется в приложении, файловая операция происходит во временной папке операционной системы, по крайней мере, в первый раз. Предположим, что есть несколько серверов, и сеанс создается на первом сервисе. Когда вы снова отправляете запрос и запрос попадает на другой сервер, информация о сеансе не существует, и вы получаете ответ «не прошедший проверку подлинности». Я знаю, вы можете обойти это с помощью липкой сессии. Однако при аутентификации на основе токенов эта проблема решается естественным образом. Нет проблемы с закрепленным сеансом, поскольку токен запроса перехватывается при каждом запросе, отправляемом на сервер.
Давайте познакомимся с использованием node+jwt(учебник по jwt) для создания простой проверки подлинности токена
Пример
Когда пользователь входит в систему в первый раз, отправьте учетную запись и пароль на сервер, и сервер пройдет проверку, и будет сгенерирован соответствующий токен.Код выглядит следующим образом:
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
//生成token的方法
function generateToken(data){
let created = Math.floor(Date.now() / 1000);
let cert = fs.readFileSync(path.join(__dirname, '../config/pri.pem'));//私钥
let token = jwt.sign({
data,
exp: created + 3600 * 24
}, cert, {algorithm: 'RS256'});
return token;
}
//登录接口
router.post('/oa/login', async (ctx, next) => {
let data = ctx.request.body;
let {name, password} = data;
let sql = 'SELECT uid FROM t_user WHERE name=? and password=? and is_delete=0', value = [name, md5(password)];
await db.query(sql, value).then(res => {
if (res && res.length > 0) {
let val = res[0];
let uid = val['uid'];
let token = generateToken({uid});
ctx.body = {
...Tips[0], data: {token}
}
} else {
ctx.body = Tips[1006];
}
}).catch(e => {
ctx.body = Tips[1002];
});
});
Пользователь сохраняет полученный токен локально через проверку:
store.set('loginedtoken',token);//store为插件
После того, как клиент запросит интерфейс, который необходимо аутентифицировать, токен будет передан на сервер в заголовке запроса:
service.interceptors.request.use(config => {
let params = config.params || {};
let loginedtoken = store.get('loginedtoken');
let time = Date.now();
let {headers} = config;
headers = {...headers,loginedtoken};
params = {...params,_:time};
config = {...config,params,headers};
return config;
}, error => {
Promise.reject(error);
})
Сервер перехватывает токены для всех интерфейсов, требующих входа в систему, и проверяет их валидность.
function verifyToken(token){
let cert = fs.readFileSync(path.join(__dirname, '../config/pub.pem'));//公钥
try{
let result = jwt.verify(token, cert, {algorithms: ['RS256']}) || {};
let {exp = 0} = result,current = Math.floor(Date.now()/1000);
if(current <= exp){
res = result.data || {};
}
}catch(e){
}
return res;
}
app.use(async(ctx, next) => {
let {url = ''} = ctx;
if(url.indexOf('/user/') > -1){//需要校验登录态
let header = ctx.request.header;
let {loginedtoken} = header;
if (loginedtoken) {
let result = verifyToken(loginedtoken);
let {uid} = result;
if(uid){
ctx.state = {uid};
await next();
}else{
return ctx.body = Tips[1005];
}
} else {
return ctx.body = Tips[1005];
}
}else{
await next();
}
});
Открытый и закрытый ключи, используемые в этом примере, можно сгенерировать самостоятельно.
- Откройте инструмент командной строки, введите openssl, откройте openssl;
- Сгенерировать закрытый ключ:
genrsa -out rsa_private_key.pem 2048
- Сгенерировать открытый ключ:
rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
читать оригинал Нажмите здесь, чтобы просмотреть фоновый код узла