前言
在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行保护,那么别人就可以很容易地获取并调用这些 API 进行操作。那么服务器端要如何进行鉴权呢?
Json Web Token 简称为 JWT,它定义了一种用于简洁、自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。
说得好像跟真的一样,那么到底要怎么进行认证呢?
首先用户登录时,输入用户名和密码后请求服务器登录接口,服务器验证用户名密码正确后,生成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 基本的流程,这或许不是最完美的,但在大多数登录中使用已经足够了。
上面的代码可能不够具体,这里使用 Koa + mongoose + vue.js 实现的一个例子 :jwt-demo ,可以做为参考。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍koa2服务端使用jwt进行鉴权及路由权限分发的流程分析,包括了koa2服务端使用jwt进行鉴权及路由权限分发的流程分析的使用技巧和注意事项,需要的朋友参考一下 大体思路 后端书写REST api时,有一些api是非常敏感的,比如获取用户个人信息,查看所有用户列表,修改密码等。如果不对这些api进行保护,那么别人就可以很容易地获取并调用这些 api 进行操作。 所以对于一些a
导入 jsonwebtoken 包 文档:https://www.npmjs.com/package/jsonwebtoken 安装:npm install jsonwebtoken egg 框架配置 config / config.default.js 中配置 jwt /********** token 配置 **********/ config.jwt = { secret: 'bcryp
我有一个Web api终端,它给我JWT令牌。它不是一个完全授权的服务器。它只是可以生成一个JWT令牌。 现在我有另一个用 aspnet 核心编写的 Web 应用程序。其中在启动中.cs我添加了以下行,以便我可以使用收到的 JWT 令牌进行授权 我也有一个登录表单(在web应用程序中),用户输入用户名和密码,我发送到web api并获得令牌。为了保护web应用程序中的任何控制器,我只使用了[Aut
我想写一个应用程序,允许与数据交互的两种RESTful形式;常规REST CRUDendpoint和Web-UI。 过去,我在JS中实现了UI的大部分功能,这将调用常规的RESTendpoint。这很好,但对于这个应用程序,我想使用Qute来执行生成页面内容的大部分基本功能。但是,为了正确地管理endpoint并确保正确的RBAC控制,我需要通过cookie而不是普通的头来访问JWT。这似乎是可能
本文向大家介绍React路由鉴权的实现方法,包括了React路由鉴权的实现方法的使用技巧和注意事项,需要的朋友参考一下 前言 上一篇文章中有同学提到路由鉴权,由于时间关系没有写,本文将针对这一特性对 vue 和 react 做专门说明,希望同学看了以后能够受益匪浅,对你的项目能够有所帮助,本文借鉴了很多大佬的文章篇幅也是比较长的。 背景 单独项目中是希望根据登录人来看下这个人是不是有权限进入当前页
本文向大家介绍ASP.NET Core使用JWT认证授权的方法,包括了ASP.NET Core使用JWT认证授权的方法的使用技巧和注意事项,需要的朋友参考一下 demo地址: https://github.com/william0705/JWTS 名词解析 认证 : 识别用户是否合法 授权: 赋予用户权限 (能访问哪些资源) 鉴权: 鉴定权限是否合法 Jwt优势与劣势 优势 1、 无状态 tok