登录鉴权机制详解:从前端到后端的全面解析

1,252 阅读5分钟

前言

     想必各位肯定碰到过这种情况,我们访问某一个网站的一个页面时,我们没有登录,直接访问某一个页面,会无法访问到我们想要访问到的页面,而是去到了登录界面。这个过程被称之为'登录鉴权',在未登录状态访问需要权限的页面时,就会触发'登录鉴权',那么下面就由VIrtual09带大家了解一下'登录鉴权'。

前端鉴权

     前端鉴权可以理解为,当用户访问需要登录权限的页面地址时,前端判断本地存储是否有用户信息数据,如果有,则认为是登录了的提及前端鉴权,那么这个时候我们就不得不需要聊一下路由守卫了。 正如其名,vue-router 提供的路由守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。

image.png

路由守卫有三种,分为'全局前置守卫','全局解析守卫','全局后置钩子',这里实现前端鉴权我们只需要用到'全局前置守卫'。

image.png

beforeEach(to,from)接受两个参数,to即将要进入的目标用一种标准化的方式,from当前导航正要离开的路由用一种标准化的方式,我们打印tofrom

router.beforeEach((to,from)=>{
  console.log(to,from);
})

image.png

我们可以很清晰的看到to是指跳转到的页面的路径,from是指从哪个页面跳转的路径。 然后,我们去思考哪一些页面是不需要用户权限就可以直接访问的,将其添加进入白名单whitePath,进入白名单的路径无需用户权限就可以访问。那么如何判断是否有用户权限访问呢,我们在浏览器本地存储中存放了数据userInfo,当我们访问飞白名单路径时,判断浏览器本地存储中是否有userInfo,如果存在就可以访问,否则跳转到登录界面。

const whitePath = ['/login','/register']
// 全局前置路由守卫
router.beforeEach((to,from,next)=>{
  console.log(to,from);
  if(!whitePath.includes(to.path)){
    //判断本地有无用户数据
    if(!localStorage.getItem('userInfo')){
      router.push('/login')
      return
    }
    next()
    return
  }
  next()
})

这里我们不得不注意一下,第三个参数next,假设我们不在if语句结束后添加next()则代码不会向下走下去,无法开启下一个过程,这里的用法跟Node.jsKoa框架中的use()方法一米一样。

后端鉴权

     后端鉴权的实现相对于前端就复杂很多,但是安全性远大于前端鉴权。我们先来捋一下思路。
第一步:我们从前端输入了正确的账号密码交给了后端
第二步:后端校验账号密码正确后,就用该账号信息生成一个加密的令牌(token),并返回给前端保存
第三步:前端接下来的所有接口请求,必须带上这个令牌token带给后端
第四步:后端校验token的合法性来判断此时用户是否权限
令牌又如何生成?
在阮一峰老师的JSON Web Token 入门教程很好的为我们介绍了

image.png

所以这里我们要自己打造一个方法实现生成令牌,在这之前我们必须在后端部分安装依赖

npm i jsonwebtoken
const jwt =  require('jsonwebtoken')

function sign(option){
    return jwt.sign(option,'999',{
        expiresIn:86400   //token过期时间1天
    })//第二个参数是签名 
}
module.exports = {
    sign
}

然后我们在后端登录部分,调用jwt.sign()方法生成一个token,接受一个参数,这个参数是一个对象,我们放入id,username,admin数据即可。

let token = jwt.sign({
                id:result[0].id,
                username:result[0].username,
                admin:true
            })

这就是我们生成的token

image.png

然后把生成的token通过koa的上下文对象ctx.body返回给前端,然后前端把数据保存在浏览器本地存储中

image.png

那么接下来我们下一步要实现前端来的所有接口请求,必须带上这个令牌token带给后端,所以我们这里打造一个请求拦截,判断浏览器本地存储是否存在token这个数据,如果存在我们就将token放在请求头中

image.png 这样任何一个接口发送请求时,我们就会通过请求头把token带给后端。
最后一步就是在后端检测前端带来的token是否合法,所以我们又要打造一个函数,用于判断前端带来的token是否合法。

function verify(){
    return (ctx,next)=>{
        let jwtToken = ctx.request.headers.authorization
        if(jwtToken){
            try {
                // 判断 token是否合法
                const decoded = jwt.verify(jwtToken,'999')
                if(decoded.id){//合法
                    next()
                }
            } catch (error) {
                ctx.body = {
                    status:401,
                    msg:'token 失效'
                }
            }
        }else{
            ctx.body = {
                status:401,
                msg:'请提供token'
            }
        }   
    }
}

第一步我们获取到请求头中的token,token存在的话,就判断这个token是否和我们打造的token一致,这里我们要注意

image.png

第二个参数签名可以帮助我们判断token是否合法,所以在函数verify(token,签名)接收参数签名用于判断,这里我们假设id存在,就表示合法,我们也可以使用username,我们给token接收了一个对象,对象中有三个属性

image.png

最后我们测试一下token

image.png

我们先给正确的token,看看打印什么

image.png

打印了测试数据
下面我们使用错误的token

image.png

就会报错,这样我们就实现了后端鉴权。

本文到此结束,若有不足,恳请各位指出,谢谢大家!!!

image.png