Lidong's blog

JWT 认证实例

欢迎访问新站点: https://www.yidiankuaile.com/post/nodejs-jwt-authentication

初始化

1
npm init -y
1
npm i express dotenv jsonwebtoken

环境变量

.env
1
2
ACCESS_TOKEN_SECRET=dbf8de
REFRESH_TOKEN_SECRET=7ac2a3

项目代码

app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
const express = require("express");
const app = express();
require("dotenv").config();
const jwt = require("jsonwebtoken");
app.use(express.json());

const posts = [
{
username: "Kyle",
title: "Post 1"
},
{
username: "Jim",
title: "Post 1"
}
];

// 临时保存 refreshTokens,实际应用可以保存到数据库中
let refreshTokens = [];

// 登录,获取accessToken、 refreshToken
app.post("/login", (req, res) => {
// Authenticate User
const username = req.body.username;
const user = { name: username };
const accessToken = generateAccessToken(user);
const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET);
refreshTokens.push(refreshToken);
res.json({
accessToken,
refreshToken
});
});

// 通过 refreshToken 获取 accessToken
app.post("/token", (req, res) => {
const refreshToken = req.body.token;
if (refreshToken == null) return res.sendStatus(401);
if (!refreshTokens.includes(refreshToken)) return res.sendStatus(403);

jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
const accessToken = generateAccessToken({ name: user.name });
res.json({ accessToken });
});
});

// 获取需要认证的文章
app.get("/posts", authenticateToken, (req, res) => {
res.json(posts.filter(post => post.username === req.user.name));
});

// 退出登录 删除 refreshToken
app.delete("/logout", (req, res) => {
refreshTokens = refreshTokens.filter(token => token !== req.body.token);
res.sendStatus(204);
});

// 认证中间件
function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (token == null) {
return res.sendStatus(401);
}
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) {
return res.sendStatus(403);
}
req.user = user;
next();
});
}

// 生成token
function generateAccessToken(user) {
return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "30s"
});
}

app.listen(3000);

请求示例

request.http
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
###
POST http://localhost:3000/login
Content-Type: application/json

{
"username":"Jim"
}

###
POST http://localhost:3000/token
Content-Type: application/json

{
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSmltIiwiaWF0IjoxNTgzNDkxMjUzfQ.aM_n0O2nt5TXBIrolk7mk9wvXvMHrhYzdJ7FdFWCd8U"
}

###
GET http://localhost:3000/posts
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSmltIiwiaWF0IjoxNTgzNDkxMjcyLCJleHAiOjE1ODM0OTEzMDJ9.W7mrj8Jr9sMQ1vIVB-uI_lZdHVCixlC3DVb3lmf9zJU

###
GET http://localhost:3000/logout
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSmltIiwiaWF0IjoxNTgzNDkxMjcyLCJleHAiOjE1ODM0OTEzMDJ9.W7mrj8Jr9sMQ1vIVB-uI_lZdHVCixlC3DVb3lmf9zJU

更新记录

  1. 2020/3/6 15:15:16 首次发布

参考链接

本文链接:


评论内容还在加载中。。。
如无法加载,请将域名 disqus.com 和 disquscdn.com 加入到你的代理规则中