当前位置: 首页 > 后端技术 > Node.js

koa从零开始搭建,实现JWT用户认证

时间:2023-04-03 20:49:00 Node.js

环境准备依赖选择与安装基于上节课提到的一些必要的依赖,我们需要安装一些依赖:md5-密码加密util-内置模块,安装jsonwebtokenasappropriate-JSONWebToken的实现(JSONWebToken入门教程)实现登录接口,我们依次创建,并实现基本功能routercontrollerservice。如果忘记了,请参考Koa从头到Api实现-项目建设密码加密一般涉及到密码等敏感信息在数据库中存储时,不可能明文存储,必须加密。而我们最常使用md5来加密简单的密码,md5加密后可以破解,稍微复杂一点的就破解不了。所以,还是很安全的。使用方法非常简单。constmd5=require('md5')md5(password)通常我们获取用户注册时输入的密码,加密后存入数据库。登录时,先对密码进行加密,再与数据库中的加密数据进行匹配。Token的组成TokenHeader-HeaderPlayload-PayloadSignature-SignatureHeader{"typ":"JWT","alg":"HS256"}从上面可以看出,token使用的是HS256加密算法,header可以使用Base64编码得到一串字符串eyJhbGciOiJIUzI1NiJ91Playload{“iss”:“OnlineJWTBuilder”,“iat”:1416797419,“exp”:1448333419,…….“userid”:10001}payload中存放了token的发行者(iss)、发行时间(iat)、过期时间(exp)等以及我们需要写入token中的一些信息。payload也经过Base64编码得到一串字符串eyJ1c2VyaWQiOjB91Signature。Header和Playload拼接生成字符串str="eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjB9",使用HS256算法和key(secret,服务器自己提供的字符串)pairstr加密生成最终的JWT,也就是我们的token需要,形式为:str."signaturestring".在服务端与客户端进行Token交互的过程中,客户端使用用户名和密码登录服务端,对用户名和密码进行验证。如果通过,则生成令牌并将其返回给客户端。客户端收到token后,每次请求都携带token(相当于一个token,表示我有权限访问),server端收到token,验证token的合法性。如果验证通过,则请求通过。否则,请求失败。如何验证Token是否合法?上面我们知道,token是我们根据Base64编码生成的,否则我们解析它,解析失败则token无效。实际登录接口的实现:constmd5=require('md5')constjwt=require('jsonwebtoken')constsecret=require('../config/secret.json')constlogin=async(obj)=>{try{if(!obj.name||!obj.password){return{err:'账号和密码不能为空',success:false}}else{constname=awaitdb.user.findAll({where:{name:obj.name}})//密码加密obj.password=md5(obj.password)//判断用户是否存在if(name.length<=0){return{success:false,err:'The当前用户不存在'}}else{letresults=awaitdb.user.findOne({where:obj})//验证用户密码if(results){//写入token信息constuserToken={name:results.name,id:results.id}//发出令牌后1小时过期consttoken=jwt.sign(userToken,secret.sign,{expiresIn:'1h'})return{success:true,token:token,data:results}}else{return{success:false,err:'密码错误'}}}}}catch(e){console.log(e)return{success:false,err:'登录失败,请联系管理member...'}}module.exports={login}我们在接口中生成一个token,并将token返回给客户端。客户端在请求时要携带这个token,服务端根据token验证自己的身份。在Koa中,我们可以通过中间件来实现Request拦截。令牌请求拦截中间件实现constjwt=require('jsonwebtoken')constsecret=require('../config/secret.json')constutil=require('util')constverify=util.promisify(jwt.verify)module.exports=function(){returnasyncfunction(ctx,next){//设置接口白名单,不进行token验证if(ctx.url==='/user/login'){awaitnext()}else{try{lettoken=ctx.header.authorization//获取请求中携带的tokenif(token){letpayloadtry{payload=awaitverify(token.split('')[1].replace(/\s/g,''),secret.sign)//解密payload,获取用户名和ID//验证合法性//if(payload.exp<=newDate()/1000){//console.log('expired')//}awaitnext()}catch(err){ctx.body={success:true,message:'登录密钥无效或过期,请重新登录',code:-1}console.log('tokenverifyfail:',err)}}else{ctx.body={success:false,message:'Verificationfailed',code:-1}}}catch(err){console.log(err)}}}}最后引入中间件,在router之前使用app.use(token())app.use(router.routes())