前言
随着 Web 应用日益增多,用户登录已成为 Web 应用中极其重要的部分,而身份认证是应用程序的关键事项之一。而一种由工业标准化组织(ISO)提出的跨域认证的解决方案 JWT(JSON Web Token)已经逐渐被广泛接受,并被越来越多的开发者用到接口的鉴权中,本文我们来介绍如何使用 Koa2 构建 JWT 身份验证系统。
JWT 的工作原理
JWT(JSON Web Token)被设计为安全地在网络间传递信息,签名信息保证了该信息不可被篡改互认。
JWT 是 JSON 对象,该对象具有头部、载荷和签名三个部分,使用 . 进行分隔表示出来。
JWT 由三部分组成,头部,载荷,签名。它们之间是用 . 分隔的字符串。
- 头部(header):声明类型和签名算法类型。
- 载荷(payload):存放需要传递的信息,比如用户的 id,用户名,过期时间等。
- 签名(signature):base64(header) + "." + base64(payload) 作为签名的原文,用密钥签名。
整个 JWT 的格式如下:xxx.yyyyy.zzzzz这三部分分别采用base64编码生成。
详细讲解 Koa2 源码实现,步骤如下。
安装依赖模块
$ npm install jsonwebtoken koa koa-router koa-bodyparser
在项目中使用了 koa 作为 Web 框架、koa-router 作为路由,可以很好地与 JWT 身份认证融合。
配置 jwt 和 secret
首先第一个要做的就是定义配置文件,这个配置文件必须要注册到服务端,因此在 Koa2 中定义中间件。
// javascriptcn.com 代码示例 const jwt = require("jsonwebtoken"); const util = require("util"); const verify = util.promisify(jwt.verify);//解密 const secret = "secret"; const createToken = (payload, secret, expiresIn) => jwt.sign(payload, secret, { expiresIn }); async function JWTAuth(ctx, next) { const token = ctx.header.authorization; try { const payload = await verify(token.split(" ")[1], secret); ctx.payload = payload; } catch (err) { ctx.throw(401, err.message); } await next(); } module.exports = { createToken, JWTAuth };
主要实现功能:加密,解密和验证用户是否登录。
这个文件中,我们定义了一个 secret 签名算法,实现了用户加密、解密的 API,也可以定义其有效期。
创建用户模型
// javascriptcn.com 代码示例 const crypto = require("crypto"); const mongoose = require("mongoose"); const userSchema = new mongoose.Schema( { username: { type: String, required: [true, "Username required"], unique: [true, "Username already exists"], lowercase: true, trim: true, }, email: { type: String, required: [true, "Email required"], unique: [true, "Email already exists"], lowercase: true, trim: true, }, password: { type: String, required: [true, "Password required"], trim: true, }, salt: String, }, { timestamps: true } ); userSchema.pre("save", function (next) { if (this.password === undefined || this.password === "") { return next(); } this.salt = crypto.randomBytes(16).toString("hex"); this.password = crypto .pbkdf2Sync(this.password, this.salt, 10000, 64, "sha256") .toString("hex"); next(); }); userSchema.methods.comparePassword = function comparePassword(password) { const hashed = crypto .pbkdf2Sync(password, this.salt, 10000, 64, "sha256") .toString("hex"); return this.password === hashed; };
这个文件定义了一个 User 实体,它处理用户信息,包括密码、邮箱、用户名、盐等。在这个实体中,我们还定义了一个方法,用于对比密码。
用户登录逻辑
这个逻辑比较简单,我们通过邮箱和密码来验证用户的登录信息。
// javascriptcn.com 代码示例 router.post("/login", async (ctx) => { const { email, password } = ctx.request.body; const user = await User.findOne({ email }); if (!user) { ctx.status = 401; ctx.body = { message: "User does not exist", }; return; } if (!user.comparePassword(password)) { ctx.status = 401; ctx.body = { message: "Password is invalid", }; return; } const token = createToken({ user: user._id }, secret, "30m"); ctx.cookies.set("token", token, { maxAge: 1000 * 60 * 60 * 24, httpOnly: true, }); ctx.body = { token }; });
检查登录状态
定义了 JWT 中间件后,只需要将其加载到任何需要检查用户是否登录的路由中即可。
router.get("/posts", JWTAuth, async (ctx) => { const posts = await Post.find().sort({ createdAt: -1 }).exec(); ctx.body = { posts, }; });
总结
这篇文章我们主要介绍了使用 Koa2 构建 JWT 身份验证系统的相关知识点和实现,JWT 是现今常用的身份认证解决方案之一,通过了解 JWT 的基本工作原理,我们可以更好地理解如何使用它。本文中提供的示例代码可以为您在实际项目中实现 JWT 身份验证提供一些参考。
参考资料
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6543401b7d4982a6ebce6f17