1.什么是身份验证
日常生活中的身份验证的场景: 比如进入公司的大楼时,需要携带工牌;打卡上班时,需要指纹识别;打开工作电脑时,需要输入密码。
2. 什么是 JSON 网络令牌?
JSON Web Token (JWT) 是一个开放标准 ( RFC 7519 ),用于在各方之间作为 JSON 对象安全地传输信息。就是通过用户名和密码来生成token确认用户的身份,确认过身份的用户称为为授权用户(Authenticated user)。
全称 JSON Web Token
, 是目前最流行的跨域认证解决方案。基本的实现是服务端认证后,生成一个 JSON
对象,发回给用户。用户与服务端通信的时候,都要在请求头带上这个 JSON
对象
3. JSON 网络令牌的作用
-
授权:这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,允许用户访问该令牌允许的路由、服务和资源。
4. JSON Web Token 结构
在其紧凑形式中,JSON Web Tokens 由用点 ( .
)分隔的三个部分组成,它们是:
-
标题
{"alg":"HS256","typ":"JWT"}
-
有效载荷
{"username":"letao","password":"123456","iat":1634524068,"exp":1634527668}
-
签名
因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz
JWT格式:
5.JSON 网络令牌如何工作?
在身份验证中,当用户使用其凭据成功登录时,将返回 JSON Web Token。由于令牌是凭证,因此必须非常小心以防止出现安全问题。通常,您不应将令牌保留的时间超过所需的时间。
每当用户想要访问受保护的路由或资源时,用户代理应该发送 JWT,通常在使用Bearer模式的Authorization标头中。标题的内容应如下所示:
Authorization: Bearer <token>
5.代码实现
文档地址: jsonwebtoken - npm
-
安装
jsonwebtoken
yarn add jsonwebtoken
2.controller目录user.js
登录成功之后使用jsonwebtoken根据用户名和密码生成token返回
const userModel = require('../model/user'); const { validator, cryptoPwd } = require('../utils/utils'); const { config:{encrypStr , secret} } = require('../config/config'); const jwt = require('jsonwebtoken'); // 用户登录 module.exports.login = async (ctx) => { // 1. 获取登录信息 const { username, password } = ctx.request.body; let msg = validator.checkUserName(username) || validator.checkPassword(password) if (msg) { ctx.body = { msg, status: 1010 } } // 2. 登录 const result = await userModel.login(username, cryptoPwd(password + encrypStr)); const token = await jwt.sign({ username, password }, secret, { expiresIn: 36 * 60 * 60 }); // if (result[0]) { ctx.body = { status: 200, token, msg: '登录成功' } } else { ctx.body = { status: 1040, msg: '登录失败' }; } }
复制
3.验证JSON Web 令牌的 Koa 中间件
文档地址:koa-jwt - npm
4.安装koa-jwt
yarn add koa-jwt
5.app.js
const Koa = require('koa') // 引入KOA const app = new Koa() // 创建KOA应用实例 const views = require('koa-views') // 处理动态模板 const json = require('koa-json') // 格式化输出的json const onerror = require('koa-onerror') // 捕获异常 const bodyparser = require('koa-bodyparser') // 处理post请求 const logger = require('koa-logger') // 日志记录 const dotenv = require('dotenv'); var xmlParser = require('koa-xml-body'); var jwt = require('koa-jwt'); const {config:{secret}} = require('./config/config'); // 启动Node env环境 dotenv.config(); // 加载路由 const order = require('./routes/order') const user = require('./routes/user') // error handler 错误处理 onerror(app) app.use(xmlParser()); // middlewares 使用中间件 app.use(function(ctx, next){ return next().catch((err) => { if (401 == err.status) { ctx.status = 401; ctx.body = 'Protected resource, use Authorization header to get access\n'; } else { throw err; } }); }); app.use(jwt({ secret }).unless({ path: [/^\/public/, /^\/login/]})) app.use(bodyparser({ enableTypes: ['json', 'form', 'text'] })) app.use(json()) app.use(logger()) app.use(require('koa-static')(__dirname + '/public')) // 动态文件模板处理 app.use(views(__dirname + '/views', { extension: 'pug' })) // logger 日志输出 app.use(async (ctx, next) => { const start = new Date() await next() const ms = new Date() - start console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) }) // routes 注册路由 app.use(order.routes(), order.allowedMethods()) app.use(user.routes(), user.allowedMethods()) // error-handling 错误处理 app.on('error', (err, ctx) => { console.error('server error', err, ctx) }); module.exports = app
复制
6.参考资料:
-
koa-jwt: koa-jwt - npm
-
mysql:mysql - npm
-
crypto加密: Crypto | Node.js v14.21.3 Documentation
-
koa: Koa (koajs) -- 基于 Node.js 平台的下一代 web 开发框架 | Koajs 中文文档
-
jwt: JSON Web Token Introduction - jwt.io
-
jsonwebtoken: jsonwebtoken - npm