JWT
1. Жетон
-
Что такое токен?
Токен относится к учетным данным для доступа к ресурсам. Это метод аутентификации личности. Это самый популярный способ решения междоменной аутентификации.
-
Зачем использовать токен?
В прошлом было более популярно использовать сеанс для аутентификации личности. Сеанс используется для аутентификации личности путем сохранения данных сеанса на сервере. Этот метод приведет к чрезмерной нагрузке на сервер при высокой степени параллелизма. Кроме того, если это кластер серверов , Тогда вам нужен общий доступ к сеансу сервера.
Токен сохраняет данные сеанса не на сервере, а в клиенте. Токен хранится в заголовках каждого запроса, и сервер определяет действительность токена и возможность доступа к ресурсу.
-
Разница между традиционным токеном и JWT
-
Традиционный жетон
Пользователь инициирует запрос на вход. После успешного входа токен возвращается и сохраняется в базе данных. Пользователю необходимо носить токен при доступе к ресурсам. Сервер получает токен и сравнивает его с базой данных.
-
JWT
Пользователь инициирует запрос на вход, и токен возвращается после успешного входа в систему, но он не существует в базе данных.Пользователь должен носить токен при доступе к ресурсам.После того, как сервер получает токен, он проверяет действительность Жетон.
-
2. Процесс внедрения JWT
-
JWT разделен на три части: заголовок, полезная нагрузка, проверка подписи.
-
header
Внутри содержит алгоритм подписи, тип токена, а затем преобразует его в строку с помощью алгоритма base64url.
//明文例子: { "alg":"HS256", "typ":"JWT" }
-
payload
Внутри содержит стандартные данные JWT и пользовательские данные, а затем преобразует их в строку с помощью алгоритма base64url.
Общие стандартные данные JWT:
- ИСС: провайдер.
- sub: тема, обычно идентификатор пользователя.
- exp: Срок годности.
- иат: время создания.
- jti: уникальный идентификатор токена.
Необязательное использование вышеуказанных стандартных данных
//明文例子: { "id": 3, "name": "Bmongo", "age": 18, "iat": 1588139323, "exp": 1588139333 }
Примечание. Поскольку JWT по умолчанию не зашифрован, не храните здесь конфиденциальную информацию.
-
verify signature
Эта часть является подписью первых двух частей для предотвращения подделки данных.
секрет - это ключ, сохраненный на стороне сервера, знает только сторона сервера, а затем используйте алгоритм подписи, указанный в заголовке, чтобы подписать две вышеуказанные части, и сгенерируйте подпись в соответствии со следующей формулой
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
После вычисления подписи просто пропустите три части, разделите их и верните пользователю.
Пример JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTAsIm5hbWUiOiLlvKDkuIkiLCJhZ2UiOjE2LCJpYXQiOjE1ODgxMzkzMjMsImV4cCI6MTU4ODEzOTMzM30.WzZp_aNgiw4iTsX7buxMhZe0z0e94Ve6ImEZ8L8L78c
-
запрос клиента
Каждый запрос клиента должен принести этот токен, обычно записывая токен в заголовки запроса.
3. Используйте в Node.js
Использование JWT в Node.js
1. Начать
Генерация и проверка токена выполняются через пакет npm jsonwebtoken.
npm install --save jsonwebtoken
2. Сгенерируйте и проверьте токен
const jwt = require("jsonwebtoken")
//撒盐,加密时候混淆
const secret = '113Bmongojsdalkfnxcvmas'
//生成token
//info也就是payload是需要存入token的信息
function createToken(info) {
let token = jwt.sign(info, secret, {
//Token有效时间 单位s
expiresIn:60 * 60 * 10
})
return token
}
//验证Token
function verifyToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(token, secret, (error, result) => {
if(error){
reject(error)
} else {
resolve(result)
}
})
})
}
3. Используйте
const express = require("express")
const app = express()
const jwt = require("jsonwebtoken")
//撒盐,加密时候混淆
const secret = '113Bmongojsdalkfnxcvmas'
const user = {
id:10,
name:"Bmongo",
age:16,
}
//生成token
//info也就是payload是需要存入token的信息
function createToken(info) {
let token = jwt.sign(info, secret, {
//Token有效时间 单位s
expiresIn:60 * 60 * 10
})
return token
}
//验证Token
function verifyToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(token, secret, (error, result) => {
if(error){
reject(error)
} else {
resolve(result)
}
})
})
}
//设置允许跨域
app.use(function(req, res, next) {
//指定允许其他域名访问 *所有
res.setHeader("Access-Control-Allow-Origin", "*");
//允许客户端请求头中带有的
res.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
//允许请求的类型
res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.setHeader("X-Powered-By",' 3.2.1')
//让options请求快速返回
if(req.method=="OPTIONS") res.send(200);
else next();
});
//白名单
const whiteList = ['/login']
app.use((req,res,next) => {
if(!whiteList.includes(req.url)) {
verifyToken(req.headers.authorization).then(res => {
next()
}).catch(e => {
res.status(401).send('invalid token')
})
} else {
next()
}
})
app.post('/login',(req,res) => {
let token = createToken(user)
res.json({token})
})
app.get("/api/info", (req,res) => {
res.send({
result:1,
data:{
"name":"Bmongo",
"id":1
}
})
})