vue jwt 认证

JWT 认证

什么是jwt?

JSON Web Token (JWT) 是目前最流行的跨域身份验证解决方案
解决问题: session 不支持分布式架构,无法支持横向扩展,只能通过数据库来保存会话数据实现共享。如果持久层失败会出现认证失败。
优点: 服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

JWT包含了使用 . 分割的三部分

  • Header 头部

    {"alg":"HS256","typ":"JWT"}
    //"alg":"HS256"=>algorithm:HS256
    //"tpy":"JWT"=>type:JWT
    
  • Payload 载荷

iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

  • Signature 签名
    对前两部分(Header,Payload)的签名,防止数据篡改

    HMACSHA256(
     base64UrlEncode(header) + "." +
     base64UrlEncode(payload),
     secret)
    

    JWT作为一个令牌(token),有些场合可能会放到URL(比如api.example.com/?token=xxx)。Base64有三个字符 +、/和=,在URL中有特殊的含义,所以要被替换掉:=被省略;+替换成-,/替换成 _ 这就是Base64URL算法。

使用方式
HTTP请求的头信息Authorization字段里面

Authorization: Bearer <token>

通过URL传输

http://www.xxx.com/pwa?token=xxxxx

POST请求放在请求体总也可

使用 vue-cli3 创建项目

vue create <project-name>

一、服务端返回签发的 token

这里服务端采用的是express,第三方模块有 body-parser, jsonwebtoken

在用户登录和客户端路由跳转时分别进行token的发送和权限的校验

//登录时根据用户名返回对应的token
app.post('/login',(req,res)=>{
   let {username} = req.body;
   if(username === 'admin'){ // 如果访问的是admin 种植cookie
        res.json({
            code:0,
            username:'admin',//这里的secret是密钥,我这里是定义的是一个字符串: let secret = 'siran'
            token:jwt.sign({username:'admin'},secret,{
                expiresIn:20  
            })
        })
   }else{
       res.json({
           code:1,
           data:'用户名不存在'
       })
   }
});
//路由跳转时根据token检查权限
app.get('/validate',(req,res)=>{
    let token = req.headers.authorization;
    jwt.verify(token,secret,(err,decode)=>{ // 验证token的可靠性
        if(err){
            return res.json({
                code:1,
                data:'token失效了'
            })
        }else{
            res.json({ 
                username:decode.username,
                code:0, // 给token续命
                token:jwt.sign({username:'admin'},secret,{
                    expiresIn:20  
                })
            })
        }
    });
});

二、路由配置

  • Home.vue 首页
  • Profile.vue 个人中心
  • Login.vue 登录页面
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
  {
    path: '/',
    name: 'home',
    component: Home,
  },
  {
    path: '/profile',
    name: 'profile',
    component: Profile,
    meta: { needLogin: true }, // 路由跳转时进行校验,必须登录了才能访问当前路由组件
  },
  {
    path: '/login',
    name: 'login',
    component: Login,
  },
],
});

三、axios封装

这里封装axios的目的主要有以下3点:

  • 为每一个请求都设置拦截器,从而让每一个请求都可以带上 token
  • 之后在每一次请求时不用写完整请求路径,设置baseURL
  • 使整个请求响应的流程更符合Vuex的设计
import axios from 'axios';

class  AjaxRequest{
constructor() {
  this.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : '/'; // 请求路径 
  this.timeout = 3000; // 设置超时时间
}

setInterceptor(instance) { // 设置拦截器
  instance.interceptors.request.use(config => {
    config.headers.Authorization = `${localStorage.getItem('token')}`;
    return config; // 让请求带上token,前提是服务端允许请求头带上 Authorization字段
  }, (err) => {
    Promise.reject(err);
  });

  instance.interceptors.response.use(res => res.data, (err) => {
    Promise.reject(err);
  });
}

request(request) {
  const instance = axios.create();
  const config = {
    baseURL: this.baseURL,
    timeout: this.timeout,
    ...request,
  }; // 合并配置
  this.setInterceptor(instance);
  return instance(config);
}
}

export default new AjaxRequest();

四、测试接口

接口文件单独写在了 api 这个目录下

import fetchData from '刚刚封装的axios'

export const getTest = () => fetchData.request({ url: '/test' });
export const login = username => fetchData.request({
url: '/login',
method: 'POST',
data: {
  username,
},
});
export const validate = () => fetchData.request({ url: '/validate' });

五、在Vuex中发送请求

export default new Vuex.Store({
  state: {
    username: '',
  },
  mutations: {
    setUsername(state, username) {
      state.username = username;
    },
  },
  actions: {
    async login({ commit }, username) {
      const r = await login(username); // 登录成功后返回用户名信息
      if (r.token) { // 如果有返回token说明成功
        commit('setUsername', username); // 将用户存入state中
        localStorage.setItem('token', r.token); // 将token存放起来
      } else { // 否则返回失败的promise
        return Promise.reject(r);
      }
    },
  },
});

六、权限认证

在登录成功之后给我们返回token后,用户在通过路由跳转不同的路由组件时需要对用户的权限进行验证,使用路由的全局守卫来针对每一个路由进行校验

router.beforeEach(async (to, from, next) => {
  const isLogin = await store.dispatch('validate');
  if (isLogin) {
    // 如果已经登录过了
    if (to.name === 'login') {//如果即将跳转的路由还是登录,则跳转到profile
      next('/profile');
    } else {
      next();
    }
  } else { //如果没有登录过,则检查要跳转的路由需不需要登录权限
    const flag = to.matched.some(item => item.meta.needLogin);
    if (flag) {
      next('/login');
    } else {
      next();
    }
  }
});

Vuex actions中验证的方法

async validate({ commit }) {
    const r = await validate();//调用api中的接口
    if (r.code === 1) {
        return false;
    }
    commit('setUsername', r.username);
    localStorage.setItem('token', r.token); // 将token存放起来
    return true;
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值