原因是http是一个无状态的协议,需要知道是哪个用户,所以需要一个校验机制。随着技术的发展和分布式web应用的普及,通过session管理用户登录状态的成本越来越高。所以逐渐发展成token的方式来进行登录身份验证,然后使用token来获取redis中缓存的用户。资料,随着后来jwt的出现,验证方式更加简单方便。不需要经过redis缓存,直接根据token获取保存的用户信息,检查token是否可用。单点登录更简单。具体认证实现过程如下:什么是jwtJSONWebToken(JWT)是一个开放标准(RFC7519),它定义了一种紧凑的、自包含的方法,用于在各方之间安全地传输JSON对象信息。此信息可以被验证和信任,因为它是经过数字签名的。jwt的组成JWT由三段信息组成,这三段信息文本链接在一起形成一个Jwt字符串。就像这样:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ第一部分我们称它为头部(header),第二部分我们称其为载荷(payload,类似于飞机上承载的物品),第三部分是签证(signature).jwtencryptionprocess1.Thefrontendinitiatesaloginrequestlogin({commit},userInfo){const{username,password}=userInforeturnnewPromise((resolve,reject)=>{login({username:username.trim(),password:password}).then(response=>{commit('SET_TOKEN',response.token)setToken(response.token)resolve()}).catch(error=>{reject(error)})})}2.Thebackendacceptsparametersforloginverificationthis.app.jwt.sign({username:username},this.app.config.jwt.web.secret,{expiresIn:expiresIn})Asabove,thebackendcodeusestheeggframeworkofnodejs,usingtheegg-jwtplug-inforencryptionanddecryption;theusernameinthecodeistheuseraccount(id),thesecretistheencryptedsaltvalue(neededfordecryption),andexpiresInisthevalidtimeofthegeneratedtoken.Aftertheaccountpasswordisverified,youcancustomizeyourencryptedcontent(payload),andthesamplecodeaddsusername.当然你也可以添加你的userInfo等,将生成的toekn返回给前端(思路:很多编程小白喜欢登录成功后直接返回用户信息,笔者不推荐这样做;这里我们只返回token,前端获取返回的token并保存)3.登录成功后,前端保存tokenlogin({username:username.trim(),password:password}).then(response=>{commit('SET_TOKEN',response.token)//登录成功后存储token,可以存储在vuex或本地setToken(response.token)resolve()}).catch(error=>{reject(error)})jwt解密流程1.前端发起请求,axios请求拦截headersservice.interceptors.request.use(config=>{//在请求发送前做一些事情if(store.getters.token){//让每个请求都携带token//['X-Token']为自定义headerskey//请根据实际情况修改config.headers['Authorization']=getToken()}returnconfig},error=>{//dosomethingwithrequesterrorconsole.log(error)//fordebugreturnPromise.reject(error)})作者在这里使用了axios库拦截器。具体使用方法参考:https://www.jianshu.com/p/86122178002a2。服务器解析标头tokenconst{Status,Code}=ctx.app.configif(ctx.get('Authorization')){//取出tokenlettoken=ctx.get('Authorization');try{//解密tokenctx.app.jwt.verify(token,secret);}catch(error){if(error.name=='TokenExpiredError'){//令牌过期ctx.responseMsg(Status.FAIL.UNAUTHORIZED,{msg:Code.FAIL.TOKEN_EXPIRED.MSG});返回;}else{ctx.responseMsg(Status.FAIL.UNAUTHORIZED,{msg:Code.FAIL.TOKEN_EXPIRED.MSG});返回;}}等待下一个();}else{//非法ctx.responseMsg(Status.FAIL.UNAUTHORIZED,{msg:Code.FAIL.ILLEGAL_TOKEN.MSG});返回;}token:请求头中获取的tokencret:salt值,与加密后一致。解密工作使用中间件。egg中间件参考:https://eggjs.org/zh-cn/basics/middleware.html3.服务端根据返回的约定代码做输出相关的响应service.interceptors.response.use(response=>{//如果自定义代码不为20000,则判断为错误。constres=response.data;if(res.code!==20000){Message({message:res.msg||'Error',type:'error',duration:5*1000})}else{returnres}},错误=>{//console.log(error)//用于调试Message({message:error.message,type:'error',duration:5*1000})if(error.response.status==401){MessageBox.confirm('您已注销,您可以取消留在该页面,或重新登录','确认注销',{confirmButtonText:'重新登录',cancelButtonText:'取消',type:'warning'})。then(()=>{store.dispatch('user/resetToken').then(()=>{location.reload()})})}elseif(error.response.status==422){}返回Promise.reject(错误)})里面的代码是根据和后端人员约定好的。可以参考restful风格:https://zhuanlan.zhihu.com/p/66148320?utm_source=wechat_session&utm_medium=social&utm_oi=986957734650208256如上,可以实现jwt-basedauthentication(p.写一次,如果不会写不好,大佬们轻点下手)
