Недавно я сделал список для себя, ммм ... список, вероятно, следующим образом:
- Рендеринг на стороне сервера React SSR
- jwt-аутентификация пользователя
- Семейный ковш Vue
- Разработка мини-программы WeChat
- ... так далее
好吧,谁让自己菜呢,没什么好抱怨的,一个一个来吧。正好最近看了一些token做身份认证的文章,发现其中大部分都是说token登录怎么怎么好,反正没有几个认认真真的实现的。 . .正好,秉着我是小白我怕谁的原则,继续分享一下express + jwt的填坑经历。为什么题目起名是最轻实践呢?因为确实看完这个你可以大概理解token登录的好处以及如何简单的实现一个前后端通过token进行认证的小系统。这个demo是在我第一篇文章那个脚手架上跑起来的,感兴趣的还可以回顾一下----->express-react-scaffold.具体实现就是下面这个样子:
- Обычный просмотр страниц без проверки токена
- Страница, которую необходимо проверить, токенизирована
- Если информация о токене отсутствует или срок действия информации о токене истек, пользователю предлагается снова войти в систему и он переходит на страницу входа.
- После успешного входа в систему каждый запрос содержит информацию о токене.
Эта статья включает
- Зачем использовать токен для аутентификации (другой режим — сеанс)
- Настройки внешнего перехватчика http-запросов
- Backend Express + jsonwebtoken реализует аутентификацию пользователей на основе токенов.
что такое токен
Два способа аутентификации личности
В системе, в которой внешний и внутренний интерфейсы разделены, аутентификация личности очень важна.В настоящее время широко используются два метода аутентификации личности:
- на основе файлов cookie
Аутентификация на стороне сервера на основе файлов cookie известна как сеанс, который генерирует данные сеанса, связанные с пользователем, на стороне сервера, отправляет идентификатор сеанса клиенту и сохраняет его в файле cookie, так что идентификатор сеанса можно использовать для проверки существования на стороне сервера, когда клиент запрашивает данные сеанса для завершения аутентификации пользователя. - Токен на основе
Аутентификация пользователей на основе токенов — это метод аутентификации без сохранения состояния на стороне сервера, и стороне сервера не нужно хранить данные токенов. После аутентификации пользователя сервер генерирует токен (хэш или зашифрованный) и отправляет его клиенту, который может поместить его в файл cookie или localStorage (sessionStorage), и каждый запрос приносит токен в заголовок, а сервер получает токен и проходит верификацию, после чего можно подтвердить личность пользователя.
Преимущества аутентификации по токену
- Небольшой размер (строка строк), поэтому скорость передачи высокая
- Существуют различные методы передачи, такие как заголовок HTTP (рекомендуется), URL, POST. Параметры и другие методы для передачи строгой структуры. Он сам (в полезной нагрузке) содержит все сообщения проверки, связанные с пользователем, такие как доступные пользователю маршруты, периоды действия доступа и т. д. Серверу не нужно подключаться к базе данных для проверки достоверности информации, а полезная нагрузка поддерживает настройку приложений и перекрестную проверку подлинности домена, в основном используемую для единого входа. Полностью полагаться на API без сохранения состояния в соответствии с принципами проектирования RESTful (HTTP без сохранения состояния).
- После того, как пользователь войдет в систему, сервер вернет строку токенов и сохранит ее локально, то есть клиент.После этого доступ к серверу должен принести эту строку токенов, чтобы получить доступ к связанным с сервером маршрутам, сервисам и ресурсы. Простота внедрения CDN, распределенное управление статическими ресурсами
- При традиционной аутентификации сеанса сервер должен сохранить идентификатор сеанса для аутентификации с помощью файла cookie, переданного пользователем. Вначале sessionID будет храниться только на одном сервере, поэтому на него может ответить только один сервер.Даже если другие серверы простаивают, они не смогут ответить, поэтому преимущества распределенных серверов не могут быть использованы в полной мере. JWT полагается на локальное сохранение информации о проверке на стороне клиента и не требует использования информации, сохраненной сервером для проверки, поэтому любой сервер может ответить, и ресурсы сервера также используются лучше.
- Улучшенная поддержка нативных мобильных приложений Нативные мобильные приложения плохо поддерживают файлы cookie и сеансы, но лучше поддерживают методы токенов.
Состав JWT
Суть JWT на самом деле представляет собой строку, состоящую из трех частей: заголовок + полезная нагрузка + подпись.
// Header
{
"alg": "HS256",//所使用的签名算法
"typ": "JWT"
}
// Payload
{
//该JWT的签发者
"iss": "luffy",
// 这个JWT是什么时候签发的
"iat":1441593502,
//什么时候过期,这是一个时间戳
"exp": 1441594722,
// 接收JWT的一方
"aud":"www.youdao.com",
// JWT所面向的用户
"sub":"any@126.com",
// 上面是JWT标准定义的一些字段,除此之外还可以私人定义一些字段
"form_user": "fsdfds"
}
// Signature 签名
将上面两个对象进行base64编码之后用.进行连接,然后通过HS256算法进行加密就形成了签名,一般需要加上我们提供的一个密匙,例如secretKey:'name_luffy'
const base64url = require('base64url')
const base64header = base64url(JSON.stringify(header));
const base64payload = base64url(JSON.stringify(payload));
const secretKey = 'name_luffy';
const signature = HS256(`${base64header}.${base64payload}`,secretKey);
// JWT
// 最后就形成了我们所需要的JWT:
const JWT = base64header + "." + base64payload + "." + signature;
// 它长下面这个样子:
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
Как работают JWT
я с официального сайтаJWT.ioНа картинке, сделанной для демонстрации, показан следующий процесс, который очень детализирован.Кроме того, есть некоторые детали, например, какую форму хранить, куда вставлять в голову, где хранить клиента и т. д. Официальный сайт имеет более подробную информацию Введение, каждый может пойти и посмотреть.
Как использовать эту штуку для аутентификации личности на переднем и заднем концах
идеи
Далее я подробно опишу, как использовать jwt для внешней и внутренней аутентификации Конкретные идеи заключаются в следующем:
- Логика входа и регистрации пользователя не требует аутентификации, потому что нет идентификационной информации пользователя и статуса входа;
- После того, как пользователь входит в систему, серверная часть генерирует токен и возвращает его во внешний интерфейс.После того, как внешний интерфейс получает токен, токен кэшируется локально, а localStorage также может быть файлом cookie для последующего использования. .
- Другой контент включает в себя взаимодействие между интерфейсом и сервером, и интерфейсу необходимо поместить информацию о аутентифицированном токене в заголовок запроса и передать его серверу.
- Когда бэкэнд получает запрос, он сначала проверяет токен.Если токен действителен (токен правильный и не просроченный), он выполняет next(), в противном случае он возвращает 401 и соответствующее сообщение напрямую.
Конкретные детали реализации входа с токеном
- Серверная часть: экспресс-jwt + jsonwebtoken Сначала установите два пакета
yarn add express-jwt jsonwebtoken
После этого токен генерируется в процессе входа в систему и возвращается во внешний интерфейс.
// /routes/user.js
if (user !== null) {
// 用户登录成功过后生成token返给前端
let token = jwt.sign(tokenObj, secretKey, {
expiresIn : 60 * 60 * 24 // 授权时效24小时
});
res.json({
success: true,
message: 'success',
token: token
});
}
Во-вторых, настройте промежуточное ПО, которое перехватывает токены, включая проверку токена и возврат сообщений об ошибках:
// jwt.js,token中间件
const expressJwt = require("express-jwt");
const { secretKey } = require('../constant/constant');
// express-jwt中间件帮我们自动做了token的验证以及错误处理,所以一般情况下我们按照格式书写就没问题,其中unless放的就是你想要不检验token的api。
const jwtAuth = expressJwt({secret: secretKey}).unless({path: ["/api/user/login", "/api/user/register"]});
module.exports = jwtAuth;
// constant.js
// 设置了密码盐值以及token的secretKey
const crypto = require('crypto');
module.exports = {
MD5_SUFFIX: 'luffyZhou我是一个固定长度的盐值',
md5: (pwd) => {
let md5 = crypto.createHash('md5');
return md5.update(pwd).digest('hex');
},
secretKey: 'luffy_1993711_26_jwttoken'
};
Наконец, поместите промежуточное ПО jwt перед промежуточным ПО маршрутизации.
// routes/index.js
// 所有请求过来都会进行身份验证
router.use(jwtAuth);
// 路由中间件
router.use((req, res, next) => {
// 任何路由信息都会执行这里面的语句
console.log('this is a api request!');
// 把它交给下一个中间件,注意中间件的注册顺序是按序执行
next();
});
Внутренняя логическая часть завершена, а следующая часть — внешняя реализация.
- Внешний интерфейс: перехватчик axios + токен хранилища localStorage Передняя часть в основном делает две вещи:
Во-первых, сохраните токен, возвращенный после успешного входа на стороне клиента. Вы можете использовать localStorage или файлы cookie. Я думаю, что официальная рекомендация — использовать localStorage, поэтому я буду использовать здесь localStorage. Во-вторых, каждый запрос помещает токен в поле Authorization заголовка заголовка.
// axios拦截器
// 拦截请求,给所有的请求都带上token
axios.interceptors.request.use(request => {
const luffy_jwt_token = window.localStorage.getItem('luffy_jwt_token');
if (luffy_jwt_token) {
// 此处有坑,下方记录
request.headers['Authorization'] =`Bearer ${luffy_jwt_token}`;
}
return request;
});
// 拦截响应,遇到token不合法则报错
axios.interceptors.response.use(
response => {
if (response.data.token) {
console.log('token:', response.data.token);
window.localStorage.setItem('luffy_jwt_token', response.data.token);
}
return response;
},
error => {
const errRes = error.response;
if (errRes.status === 401) {
window.localStorage.removeItem('luffy_jwt_token');
swal('Auth Error!', `${errRes.data.error.message}, please login!`, 'error')
.then(() => {
history.push('/login');
});
}
return Promise.reject(error.message); // 返回接口返回的错误信息
});
Видно, что после успешного входа в систему токен сохраняется в localStorage, и каждый запрос будет помещать токен в поле Authorization заголовка. Если мы очистим токен из localStorage, при повторном доступе к нему будет сообщено об ошибке.Тут есть ямка, в этой записи request.headers['Authorization'] надо выставить Authorization в таком виде, иначе у бэкенда будут проблемы даже если он получит поле, и вернет 401, request.headers.Authorization или request. headers.authorization Может быть установлено успешно, и с просмотром в браузере проблем нет, но в бэкенде будет сообщено 401 и бэкэнд сможет получить только строчные буквы, то есть res.headers.authorization, а бэкенд будет отчет не определен.
Суммировать
Очень простой маленький каштан, и в статье нет технического содержания, просто играйте и тренируйтесь писать. Где код не размещен в другом месте? вexpress-react-scaffoldДобавлена регистрация входа и аутентификация по токену. Вы можете получить доступ к логике входа в систему и функции проверки токена через /login. O(∩_∩)О, ха-ха~