请求鉴权检验JWT和Token

没有JWT的世界

  1. 服务器发送了一些用户信息给浏览器保存

  1. 浏览器请求服务器的时候,会把这些信息读取出来,通过http协议发给服务器

问题:这些信息是存在浏览器端的,可以随意更改,很难防止数据被篡改、被伪造,服务器无法信任这些信息

目的:

前端鉴权的本质就是控制前端视图层的显示前端向后台所发送的请求

前端鉴权定义

前端鉴权,也叫前端身份认证指的是验证用户是否具有系统的访问权限。

前端鉴权其实就是控制前端视图层的展示和前端所有发送的请求,就像我们去坐飞机的登机牌(对应的标识,在一定的时间范围)。

前端鉴权认证方式

Token

Token是目前市面上主流用的方式,主要适用于app鉴权,微信开发平台access token也是差不多类似的思路。

Token 其实是服务器生成的一串随机字符串或者一个 json 串,用于客户端进行资源请求的令牌。

Token 一般会包含用户的相关信息,通过验证 Token 不仅可以完成身份校验,还可以获取预设的信息。

客户端可以将 token 存放于 localStroage 等容器中。客户端每次访问都传递 token,服务端解密 token,服务端就不需要存储 Session 占用存储空间,就很好的解决负载均衡多服务器的问题了。

来源:

负载均衡多服务器的情况,不好确认当前用户是否登录,因为多服务器不共享 Session。这个问题也可以将 Session 存在一个服务器中来解决,但是就不能完全达到负载均衡的效果。

Token 流程

  1. 浏览器发起一个请求,服务端验证请求中是否有token,没有则返回失败。

  1. 重定向到登录页,发起登录请求,服务端验证用户信息,生成token并返回。

  1. 浏览器拿到token并存储到本地。每次前端请求接口的时候,都需要在请求头里带上 Token 信息

  1. Token 可以在服务端设置过期时间,如果Token 过期之后,前端在请求失败回调返回code码之后,重新跳转到登录页进行重新鉴权。

JWT

后端平常用的最多的就是 JSON Web Token(JWT),也是目前最流行的跨域身份验证解决方案

JWT 组成:(header)头部. (payload )载荷. (signature)签名

node.js 签名算法

const crypto = require('crypto');//node.js 里面的加密库
function sign(info,key){//表示签名 info:信息 key:密钥
    const hmac = crypto.createHmac('sha256',key);
    hmac.update(info);
    return hmac.digest('hex');
}
//比如签名
cosnt key ='123456';//密钥是保存在服务端的,不会发送到客户端
sign('lisi',key)

服务器要发送身份信息之前,会对身份信息进行签名,拿到一个签名的结果,把身份信息和签名一起发送给客户端(info.签名),浏览器一起来保存

浏览器请求的时候,就会把之前保存的身份信息+签名一起发给服务器

服务器通过浏览器发送的这个信息就能验证有没有被篡改

header:{'alg':'HS256','type':'JWT'} //Json格式 HS256签名算法 指明类型 base64格式转换(不是加密,可以解码出来)
payload:{'name':'lisi','age':18} //服务器想传递给客户端的信息 base64
signature:header.payload==形成字符串加上密钥==>生成签名==签名结果转为base64==>signature
header 是明文,payload也是明文,签名是为了验证前两部分是否已篡改
const crypto = require('crypto');
//签名算法
function sign(){...}

function JWT(info ,key){
    const header={
        type:"JWT",
        alg:"HS256"
    };
    const headerStr = BUffer.from(JSON.stringify(header)).toString('base64');
    const payloadStr =Buffer.from(JSON.stringify(info)).toString('base64');
    const signStr = =Buffer.from(sign(headerStr + '.'+payloadStr,key)).toString('base64'););//key值用来签名
    retrun headerStr+'.'+payloadStr+'.'+signStr;
}
constt KEY ='123456"
JWT({name:"张三",age:15},KEY)

步骤:

1.用户输入其登录信息

2.服务器验证信息是否正确,并返回已签名的token

3.token储在客户端,例如存在local storage或cookie中

4.之后的HTTP请求都将token添加到请求头里

5.服务器解码JWT,并且如果令牌有效,则接受请求

6.一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。

缺点:是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦 JWT 签发,在有效期内将会一直有效。

JWT 的使用方式
  • 客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

Authorization: Bearer <token>

载荷的内容任何人都可以读到,不要放入敏感信息

除了 JWT 可以提升 token 的安全性,Refresh token 也可以。

业务接口用来鉴权的 token,我们称之为 access token。

一个专门生成 access token 的 token,我们称为 refresh token。

refresh token 的过期时间一般比较长,比如 6 个小时,access token 的过期时间比较短,比如 10 分钟。我们在实际业务中,api 调用时只传递 access token 进行鉴权。如果 access token 过期,则使用 refresh token 去授权服务器更新 access token。最终 refresh token 也过期了,这时候用户就得重新登陆了。

优缺点
优点:
  • 轻量,服务端不用存储,移动端可用

缺点:
  • 一旦派发出去,失效之前都是有效的(虽然可以解决,但是就类似于 Session 机制了)

OAuth方式

OAuth方式是个趋势,现在想要推广应用都先要接入微博、微信、QQ等登录,降低用户使用门槛,特别是微信渠道的应用,都是接入了微信开发授权登录。

前端权限的意义

1、减少/降低非法操作的可能性。

比如页面上的一个操作按钮,通过控制台来改变它的属性,如果当前用户没有权限控制,虽然点击了,但是不会有操作以后的效果;如果有权限控制的话,没有权限的用户,可以让它隐藏,用户就看不到这个按钮的存在。

2、尽可能排除减少不必要的请求,减轻服务器压力。不具备权限的请求,就应该不需要发送

3、提高用户体验

前端鉴权的使用思路

1、首先制作一个404提示界面,然后在路由最后面添加如下代码:

{
  path:"*", //如果前面的路由没有匹配到时,所有的错误路由都会跳转到404提示界面
  component: 404Error
}

2、在做下面所有操作的时候,都需要后台返回一个登录的数据,一般在登录页面的登录按钮中触发的点击事件,获取到后台从数据库中读取到的用户信息,从当中找出相应的数据来实现。

3、菜单控制,菜单主要是导航栏的显示,由于登录数据获取是在login界面中,而导航栏显示组件在其他组件中,所以要通过传递数据来拿到登录数据,一般是通过数据本地存储来做,但是要在最后退出登录的时候清除本地存储的数据。

4、界面的控制,如果用户没有登录,手动在地址栏输入管理界面地址,就需要跳转到登录界面;如果用户登录之后,但是手动输入非权限内的地址,应该跳转到404提示界面或者提示没有权限。

5、使用拦截器判断用户是否登录,判断token是否存在,也就是在登录方法里面做处理。登录的代码如下所示:


login(){
 this.$refs.loginForm.date(
 async login=>{
 if(!login) return
 const {data:res} =await this.$http.post("login",this.loginFrom)
 if(res.status !=200) return this.$message.error('登录失败')
 this.$store.commit('setRight',res.right)
 this.$store.commit('setUser',res.data.user)
 //将token存储到本地中
 sessionStroage.setItem('token',res.data.token)
 this.$router.push('./home')
 })
}

6、登录之后再来判断进行跳转到逻辑,通常是使用导航守卫,由于可以伪造tokenrouter 路由管理下面的代码如下所示:

//在常规路由下面添加一个方法
router.beforeEach((to,from,next)=>{
if(to.path ==='./login'){next()} //跳转到登录界面不拦截
else{
//这里是进入其他界面,首先判断有无token没有跳转到登录界面,有的话就执行 const  
  token=sessionStroage.getItem('token')
if(!token){next('./login')}
else{next()}
}
})

7、动态路由的使用,由于某些角色没有权限,所以他就不应该有这个路由,更不能地址栏输入。首先把子路由,也就是权限不够的路由注释掉,路由组件的代码如下所示:

import store from '@/store'
Vue.use(Router)
const userRule={path:'./user',component:user} //超级管理员的用户信息界面
const adminRule = {path:’./admin’,component:admin} //二级管理员
//将路由写成一个对象,只要判断这个对象中有没有其中的二级路由就行了
const ruleMapping = {
'user': userRule,
'admin': adminRule
}
//应该在前面定义,后面动态添加
export function initDynamicRoutes(){
//定义一个方法将其导出,根据二级权限,对路由规则进行动态的添加
const currentRoutes = router.options.routes
const right = store.state.right
right.forEach(item => {
item.children.forEach(item =>
//item就是二级权限
{ currentRoutes[2].children.push(ruleMapping[item.path])
})
})
router.addRoutes(currentRoutes) //router.addRoutes方法,将修改过后的路由对象重新添加router中
}

8、登录界面的逻辑,具体代码如下所示:

import {initDynamicRoutes} from '@/routes'//将方法导入进来
login(){
//登录成功之后,根据用户所具备的权限动态添加路由规则
initDynamicRoutes()
}
//需要在app.vue 当中添加如下代码:
import { initDynamicRoutes } from '@/router.js'
export default {
name: 'app',
created() { //最开始就重新加载路由规则
initDynamicRoutes()
}
}

9、请求和响应的控制,如果用户通过非常规操作手动在调试器当中将禁用的按钮变成启用的状态,此时发出的请求应该被拦截。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值