接下来我会详细讲解如何使用koa和jwt实现token验证与刷新功能,这个过程包括以下几步:
- 安装koa和jsonwebtoken模块:
npm install koa jsonwebtoken
- 初始化koa应用,配置路由和中间件:
const Koa = require('koa');
const Router = require('koa-router');
const jwt = require('jsonwebtoken');
const app = new Koa();
const router = new Router();
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = { message: err.message };
}
});
router.post('/api/login', async (ctx, next) => {
// 获取用户名和密码
const { username, password } = ctx.request.body;
// 检查用户名和密码是否正确
if (username === 'admin' && password === '123456') {
// 生成 token
const token = jwt.sign({ username }, 'my_secret');
// 把 token 发送给客户端
ctx.body = { token };
} else {
// 如果用户名或密码不正确,返回 401 错误
ctx.throw(401, '用户名或密码不正确');
}
});
router.get('/api/user', async (ctx, next) => {
// 从请求头中获取 token
const token = ctx.header.token;
try {
// 验证 token 是否正确
const decoded = jwt.verify(token, 'my_secret');
// 如果验证通过,返回用户信息
ctx.body = { username: decoded.username };
} catch (err) {
// 如果验证不通过,返回 401 错误
ctx.throw(401, 'token 失效,请重新登录');
}
});
app.use(router.routes());
app.use(router.allowedMethods());
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
在上面的代码中,我们定义了两个路由,一个是登录接口/api/login
,一个是获取用户信息接口/api/user
。在登录接口中,如果用户名和密码验证通过,就会生成一个包含用户名的 token,并把它发送给客户端;在获取用户信息接口中,会先从请求头中获取 token,然后验证它是否正确,如果验证通过,就返回用户信息。
- 测试接口是否正常工作
我们可以使用 Postman 等工具来测试接口是否正常工作。首先,我们需要向 /api/login
发送一个 POST 请求,包含用户名和密码:
POST http://localhost:3000/api/login
Content-Type: application/json
{
"username": "admin",
"password": "123456"
}
如果用户名和密码验证通过,服务器会返回包含 token 的 JSON 数据:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjM5MzE5Nzg0LCJleHAiOjE2MzkzMTk3OTZ9.wuVwQSZyew3D8R-6YoX_q5xO5QsZUhGwYV37oy1oxoE"
}
我们可以把这个 token 复制下来,然后在请求头中加入 token
字段,向 /api/user
发送GET请求:
GET http://localhost:3000/api/user
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjM5MzE5Nzg0LCJleHAiOjE2MzkzMTk3OTZ9.wuVwQSZyew3D8R-6YoX_q5xO5QsZUhGwYV37oy1oxoE
如果 token 验证通过,服务器会返回当前用户的用户名:
{
"username": "admin"
}
这说明我们已经成功实现了使用koa和jwt实现token验证与刷新功能。
示例1:使用token实现用户身份认证
在实际项目中,我们需要保护某些只有登录用户才能访问的资源或接口。在这种情况下,我们可以在路由中使用中间件来验证token是否正确。例如:
function authMiddleware(ctx, next) {
const token = ctx.header.token;
try {
const decoded = jwt.verify(token, 'my_secret');
ctx.state.username = decoded.username;
return next();
} catch (err) {
ctx.throw(401, 'token 失效,请重新登录');
}
}
router.get('/api/posts', authMiddleware, async (ctx, next) => {
// 根据用户查找文章列表
const posts = await findPostsByUsername(ctx.state.username);
ctx.body = { posts };
});
在上面的代码中,我们定义了一个authMiddleware
中间件来验证token是否正确。如果验证通过,就把用户名存储在ctx.state
对象中,然后调用next()
方法放行;否则,就返回401错误。在路由中,我们把这个中间件作为第二个参数传递进去,表示需要对/api/posts
这个路由进行身份验证。如果通过身份验证,就会返回该用户的文章列表。
示例2:使用refresh token实现token自动刷新
在实际项目中,token有时效性。如果用户长时间不操作,在token失效前,token不可用。这时候,我们可以使用refresh token,自动刷新token,延长token的有效期。示例如下:
const refreshTokens = {}; // 用于存储refresh token
router.post('/api/login', async (ctx, next) => {
const { username, password } = ctx.request.body;
// 检查用户名和密码是否正确
if (checkPassword(username, password)) {
// 生成 token 和 refresh token,并且将 refresh token 存储到服务端内存中
const token = jwt.sign({ username }, 'my_secret', { expiresIn: '1h' });
const refreshToken = jwt.sign({ username }, 'my_secret_refresh', { expiresIn: '2h' });
refreshTokens[refreshToken] = username;
// 返回 token 和 refresh token
ctx.body = { token, refreshToken };
} else {
ctx.throw(401, '用户名或密码不正确');
}
});
router.post('/api/refresh-token', async (ctx, next) => {
const { refreshToken } = ctx.request.body;
try {
// 验证 refresh token 是否正确
const decoded = jwt.verify(refreshToken, 'my_secret_refresh');
// 如果验证通过,生成新的 token,并将它发送给客户端
const username = refreshTokens[refreshToken];
const token = jwt.sign({ username }, 'my_secret', { expiresIn: '1h' });
ctx.body = { token };
} catch (err) {
// 如果验证不通过,返回 400 错误
ctx.throw(400, 'invalid refresh token');
}
});
在上面的代码中,我们在登录接口中生成了一个refreshToken,并将它存储到一个对象中。如果用户需要刷新token,就需要向/api/refresh-token
发送一个POST请求,包含refreshToken:
POST http://localhost:3000/api/refresh-token
Content-Type: application/json
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjM5MzIwMzE2LCJleHAiOjE2MzkzNDg3MTZ9.zA1AJIv_3OoIUpniJAhYaMz0LNtXH665NDDmIe9BN9s"
}
如果refreshToken验证通过,服务器会生成一个新的token,并返回给客户端:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjM5MzIwNDM3LCJleHAiOjE2MzkzMjQwMzd9.KAapczYIfNw_9g6KXlc8GAPRA_UAjd2dQHSElid6-EU"
}
这样做的好处是,即使token过期,在refreshToken仍然有效的情况下,客户端仍然可以通过向服务器请求新的token来继续访问需要登录才能访问的资源,从而提高了用户体验。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:koa+jwt实现token验证与刷新功能 - Python技术站