Node.js Koa2使用JWT进行鉴权的方法示例

作者:林鑫 时间:2024-05-02 17:05:45 

前言

在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行保护,那么别人就可以很容易地获取并调用这些 API 进行操作。那么服务器端要如何进行鉴权呢?

Json Web Token 简称为 JWT,它定义了一种用于简洁、自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。

说得好像跟真的一样,那么到底要怎么进行认证呢?

Node.js Koa2使用JWT进行鉴权的方法示例

首先用户登录时,输入用户名和密码后请求服务器登录接口,服务器验证用户名密码正确后,生成token并返回给前端,前端存储token,并在后面的请求中把token带在请求头中传给服务器,服务器验证token有效,返回正确数据。

既然服务器端使用 Koa2 框架进行开发,除了要使用到 jsonwebtoken 库之外,还要使用一个 koa-jwt 中间件,该中间件针对 Koa 对 jsonwebtoken 进行了封装,使用起来更加方便。下面就来看看是如何使用的。

生成token

这里注册了个 /login 的路由,用于用户登录时获取token。


const router = require('koa-router')();
const jwt = require('jsonwebtoken');
const userModel = require('../models/userModel.js');

router.post('/login', async (ctx) => {
 const data = ctx.request.body;
 if(!data.name || !data.password){
   return ctx.body = {
     code: '000002',
     data: null,
     msg: '参数不合法'
   }
 }
 const result = await userModel.findOne({
   name: data.name,
   password: data.password
 })
 if(result !== null){
   const token = jwt.sign({
     name: result.name,
     _id: result._id
   }, 'my_token', { expiresIn: '2h' });
   return ctx.body = {
     code: '000001',
     data: token,
     msg: '登录成功'
   }
 }else{
   return ctx.body = {
     code: '000002',
     data: null,
     msg: '用户名或密码错误'
   }
 }
});

module.exports = router;

在验证了用户名密码正确之后,调用 jsonwebtoken 的 sign() 方法来生成token,接收三个参数,第一个是载荷,用于编码后存储在 token 中的数据,也是验证 token 后可以拿到的数据;第二个是密钥,自己定义的,验证的时候也是要相同的密钥才能解码;第三个是options,可以设置 token 的过期时间。

获取token

接下来就是前端获取 token,这里是在 vue.js 中使用 axios 进行请求,请求成功之后拿到 token 保存到 localStorage 中。这里登录成功后,还把当前时间存了起来,除了判断 token 是否存在之外,还可以再简单的判断一下当前 token 是否过期,如果过期,则跳登录页面


submit(){
 axios.post('/login', {
   name: this.username,
   password: this.password
 }).then(res => {
   if(res.code === '000001'){
     localStorage.setItem('token', res.data);
     localStorage.setItem('token_exp', new Date().getTime());
     this.$router.push('/');
   }else{
     alert(res.msg);
   }
 })
}

然后请求服务器端API的时候,把 token 带在请求头中传给服务器进行验证。每次请求都要获取 localStorage 中的 token,这样很麻烦,这里使用了 axios 的请求 * ,对每次请求都进行了取 token 放到 headers 中的操作。


axios.interceptors.request.use(config => {
 const token = localStorage.getItem('token');
 config.headers.common['Authorization'] = 'Bearer ' + token;
 return config;
})

验证token

通过 koa-jwt 中间件来进行验证,用法也非常简单


const koa = require('koa');
const koajwt = require('koa-jwt');
const app = new koa();

// 错误处理
app.use((ctx, next) => {
 return next().catch((err) => {
   if(err.status === 401){
     ctx.status = 401;
     ctx.body = 'Protected resource, use Authorization header to get access\n';
   }else{
     throw err;
   }
 })
})

app.use(koajwt({
 secret: 'my_token'
}).unless({
 path: [/\/user\/login/]
}));

通过 app.use 来调用该中间件,并传入密钥 {secret: 'my_token'} ,unless 可以指定哪些 URL 不需要进行 token 验证。token 验证失败的时候会抛出401错误,因此需要添加错误处理,而且要放在 app.use(koajwt()) 之前,否则不执行。

如果请求时没有token或者token过期,则会返回401。

解析koa-jwt

我们上面使用 jsonwebtoken 的 sign() 方法来生成 token 的,那么 koa-jwt 做了些什么帮我们来验证 token。


resolvers/auth-header.js
module.exports = function resolveAuthorizationHeader(ctx, opts) {
 if (!ctx.header || !ctx.header.authorization) {
   return;
 }
 const parts = ctx.header.authorization.split(' ');
 if (parts.length === 2) {
   const scheme = parts[0];
   const credentials = parts[1];
   if (/^Bearer$/i.test(scheme)) {
     return credentials;
   }
 }
 if (!opts.passthrough) {
   ctx.throw(401, 'Bad Authorization header format. Format is "Authorization: Bearer <token>"');
 }
};

在 auth-header.js 中,判断请求头中是否带了 authorization,如果有,将 token 从 authorization 中分离出来。如果没有 authorization,则代表了客户端没有传 token 到服务器,这时候就抛出 401 错误状态。

verify.js


const jwt = require('jsonwebtoken');

module.exports = (...args) => {
 return new Promise((resolve, reject) => {
   jwt.verify(...args, (error, decoded) => {
     error ? reject(error) : resolve(decoded);
   });
 });
};

在 verify.js 中,使用 jsonwebtoken 提供的 verify() 方法进行验证返回结果。jsonwebtoken 的 sign() 方法来生成 token 的,而 verify() 方法则是用来认证和解析 token。如果 token 无效,则会在此方法被验证出来。

index.js


const decodedToken = await verify(token, secret, opts);
if (isRevoked) {
 const tokenRevoked = await isRevoked(ctx, decodedToken, token);
 if (tokenRevoked) {
   throw new Error('Token revoked');
 }
}
ctx.state[key] = decodedToken; // 这里的key = 'user'
if (tokenKey) {
 ctx.state[tokenKey] = token;
}

在 index.js 中,调用 verify.js 的方法进行验证并解析 token,拿到上面进行 sign() 的数据 {name: result.name, _id: result._id} ,并赋值给 ctx.state.user ,在控制器中便可以直接通过 ctx.state.user 拿到 name 和 _id 。

安全性

  • 如果 JWT 的加密密钥泄露的话,那么就可以通过密钥生成 token,随意的请求 API 了。因此密钥绝对不能存在前端代码中,不然很容易就能被找到。

  • 在 HTTP 请求中,token 放在 header 中,中间者很容易可以通过抓包工具抓取到 header 里的数据。而 HTTPS 即使能被抓包,但是它是加密传输的,所以也拿不到 token,就会相对安全了。

总结

这上面就是 jwt 基本的流程,这或许不是最完美的,但在大多数登录中使用已经足够了。

上面的代码可能不够具体,这里使用 Koa + mongoose + vue.js 实现的一个例子 :jwt-demo ,可以做为参考。

来源:http://www.cnblogs.com/linxin/p/9491342.html

标签:Koa2,JWT,鉴权
0
投稿

猜你喜欢

  • Go爬虫(http、goquery和colly)详解

    2024-05-08 10:52:43
  • vue-simple-uploader上传成功之后的response获取代码

    2024-06-05 15:28:44
  • 超好用:免费的图床

    2023-03-31 09:55:42
  • 用户体验中的五大要素

    2008-07-07 16:41:00
  • Quickwork For Asp -实战之后台管理

    2009-12-31 19:13:00
  • 自适应内容高度的收缩与展开

    2007-09-24 14:38:00
  • background-clip/origin一则运用

    2008-04-15 14:45:00
  • Go 语言进阶单元测试示例详解

    2024-02-07 18:17:06
  • python 子类调用父类的构造函数实例

    2023-05-27 22:33:37
  • python pycharm中使用opencv时没有代码自动补全提示的解决方案

    2022-05-10 14:34:15
  • Python基于BeautifulSoup爬取京东商品信息

    2021-03-15 21:52:53
  • 基于python实现文件加密功能

    2022-02-02 20:28:57
  • 基于python全局设置id 自动化测试元素定位过程解析

    2022-04-28 18:52:08
  • Pytorch之保存读取模型实例

    2023-04-03 02:15:11
  • 跟老齐学Python之有容乃大的list(4)

    2023-03-13 21:53:17
  • Python中ROC曲线绘制

    2023-05-28 16:38:15
  • 使用python进行文本预处理和提取特征的实例

    2022-07-13 21:25:47
  • 有效防止ASP木马上传运行—小知识[网络安全技术]

    2011-03-06 11:15:00
  • 详解MySQL中的SQRT函数的使用方法

    2024-01-28 03:59:32
  • Python使用sax模块解析XML文件示例

    2021-11-28 15:31:39
  • asp之家 网络编程 m.aspxhome.com