项目中的鉴权是如何实现的?

一、token 验证登录流程

使用基于 Token 的身份验证方法,大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

总的来说就是客户端在首次登陆以后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就行了,服务器端会拦截所有的请求,然后校验token的合法性,合法就放行,不合法就返回401(鉴权失败)。

二、最常用的鉴权是 JWT方案(JSON WEB TOKEN)

JWT是什么?

JWT是Auth0提出的通过对JSON进行加密签名来实现授权验证的方案。就是登陆成功后将相关信息组成json对象,然后对这个对象进行某中方式的加密,返回给客户端,客户端在下次请求时带上这个token,服务端再收到请求时校验token合法性,其实也就是在校验请求的合法性。

JWT对象通常由三部分构成:

Headers: 包括类别(typ)、加密算法(alg)


{
  "alg": "HS256",
  "typ": "JWT"
}

Claims :包括需要传递的用户信息

    {
      "sub": "1234567890",
      "name": "John Doe",
      "admin": true
    }

Signature: 根据alg算法与私有秘钥进行加密得到的签名字串, 这一段是最重要的敏感信息,只能在服务端解密;

HMACSHA256(  
    base64UrlEncode(Headers) + "." +
    base64UrlEncode(Claims),
    SECREATE_KEY
)

编码之后的JWT看起来是这样的一串字符:


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

三、 后端设计:nodejs+express+jwt-simple

auth.js
let jwt = require('jwt-simple');
let secret = "wangyy";
let time = 10;
 module.exports = { 
 /*
  *检验token合法性
 */ 
 validate:function(req,res,next){ 
      let token = req.body.Authorization||req.headers["Authorization"];
        if(token){ 
          let decodeToken = null;
          try { //防止假冒token解析報錯 
             decodeToken = jwt.decode(token,secret,'HS256'); 
          } catch (err) { 
            res.status(401).send("非法访问"); return; 
          } 
        let exp = decodeToken.exp; if(!exp){
        res.status(401).send("非法访问");
     }
     let now = new Date().getTime();
     if(exp>(now+time*60*1000)){
        res.send({code:'401',"errorMsg":"授权超时"})
      }
      next();
    }else{ 
       res.status(401).send("非法访问");
    }
  },
  /* 生成token*/ 
  makeToken(){ 
      let Token = null; 
      let payload = { 
              time:new Date().getTime(), 
              exp:this.makeExp(time) 
              } 
      Token = jwt.encode(payload,secret,HS256) return Token; 
 }, 
 /*生成token过期时间*/ 
 makeExp:function(time){
      let stam = time601000; 
   } 
 }

server.js

let express = require("express"); 
let app = express(); 
let bodyParser = require('body-parser'); 
let auth = require('./lib/auth.js'); 
let chalk = require('chalk'); app.use(bodyParser.json()); app.post('/login',function(req,res,next){ 
            let Token = auth.makeToken(); 
            res.json({result:"success",token:Token},200)
   });
app.use('*',[auth.validate],function(req,res,next){ 
     res.send('success'); 
  }); 
app.listen('9999')

上面只是一个简单的token生成和校验,如果有需要可以根据实际需要进行逻辑处理

四、前端设计

使用vuex保存全局状态,并做数据持久化
vuex里面面定义token变量来表示用户是否登录,初始值为’’


import createPersistedState from 'vuex-persistedstate'

export default new Vuex.Store({
	  state: {
	    token: '',
	  },
	  mutations: {
	    setIsLogin(state, isLogin) {  //登录成功调用
	      state.token = isLogin;
	    },
	    FedLogOut(state) {        //退出登陆执行
	      state.token=''
	    }
	  }
    actions,
    getters,
    plugins:[createPersistedState({  //vuex数据固化到本地缓存,数据持久化
        storage: window.localStorage
    })] 
});
配置request请求拦截器

request请求拦截器:发送请求前统一处理,如:设置请求头headers、应用的版本号、终端类型等。


service.interceptors.request.use(
  config => {
    if (store.state.token) {
     // 为请求头对象,添加token验证的Authorization字段
     config.headers.Authorization = store.state.token;     
    }
        return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
response响应拦截器

response响应拦截器:有时候我们要根据响应的状态码来进行下一步操作,例如:由于当前的token过期,接口返回401未授权,那我们就要进行重新登录的操作。


service.interceptors.response.use(
  response => {
    Toast.clear()
    const res = response.data
    if (res.status && res.status !== 200) {
      // 登录超时,token过期返回401,重新登录
      if (res.status === 401) { 
        store.dispatch('FedLogOut').then(() => {
                router.replace({
                path: '/login'
                //登录成功后跳入浏览的当前页面
                // query: {redirect: router.currentRoute.fullPath}
            })
        })
      }
      return Promise.reject(res || 'error')
    } else {
      return Promise.resolve(res)
    }
  },
  error => {
    Toast.clear()
    console.log('err' + error) // for debug
    return Promise.reject(error)
  }
)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

star@星空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值