Le projet vue stocke le jeton dans (vuex) store et localstorage


Lisez attentivement, réfléchissez encore et encore, Xiaobai va commencer! Si vous avez des questions, veuillez laisser un message❤

1. Préparation et jeton

1. Préparation
  • Comprendre
    l'introduction du jeton de jeton (session, cookie) : le jeton demande fréquemment des données au serveur côté client, et le serveur interroge fréquemment la base de données pour les noms d'utilisateur et les mots de passe et les compare pour déterminer si les noms d'utilisateur et les mots de passe sont corrects ou non, et lance les invites correspondantes. Dans ce contexte, Token a vu le jour.
    Le jeton est une chaîne de chaînes générée sur le serveur pour servir de jeton à demander par le client. Si le serveur frontal utilise le nom d'utilisateur / mot de passe pour demander l'authentification au serveur et que l'authentification du serveur réussit, le serveur renverra le jeton au serveur frontal. Le frontal peut amener Token à prouver son statut juridique à chaque fois qu'il le demande. Si ce jeton est persistant sur le serveur (tel que stocké dans une base de données), il s'agit d'un jeton d'identité permanent (sauf si une période de validité est définie).

  • Avantages du
    jeton Le jeton est entièrement géré par l'application, il peut donc éviter la politique de même origine. Le
    jeton peut éviter les attaques CSRF. Le
    jeton peut être sans état et peut être partagé entre plusieurs services pour
    réduire la pression sur le serveur, réduire les requêtes fréquentes dans la base de données et rendre le serveur plus robuste .

  • Installer vuex
    cnpm installer vuex --save

2. Introduction à l'utilisation des jetons

Lorsque les extrémités avant et arrière sont complètement séparées, l'idée générale d'implémenter la vérification des jetons dans le projet Vue est la suivante:

1. Lors de la première connexion, le frontal ajuste l'interface de connexion du back-end et envoie le nom d'utilisateur et le mot de passe

2. Le backend reçoit la demande, vérifie le nom d'utilisateur et le mot de passe, et si la vérification réussit, il renvoie un jeton au frontend

3. Le frontal obtient le jeton, stocke le jeton dans localStorage et vuex, et passe à la page de routage

4. Chaque fois que le frontal saute sur l'itinéraire, il juge s'il y a un jeton dans localStroage, saute à la page de connexion s'il n'y a pas de jeton et saute à la page de routage correspondante

5. Chaque fois que l'interface back-end est ajustée, le jeton doit être ajouté à l'en-tête de la demande

6. Le backend détermine s'il y a un jeton dans l'en-tête de la demande. S'il y a un jeton, il obtiendra le jeton et vérifiera le jeton. Si la vérification réussit, il renverra les données. Si la vérification échoue (par exemple, le jeton expire), il renverra 401. S'il n'y a pas de jeton dans l'en-tête de la demande, il renverra également 401.

7. Si le serveur frontal obtient le code d'état 401, effacez les informations du jeton et passez à la page de connexion
——————————————— Déclaration de
droit d'auteur: cet article est l'œuvre originale du blogueur du RSCI "sleepwalker_1992" L'article est conforme à l'accord de copyright CC 4.0 BY-SA. Veuillez joindre le lien source original et cette déclaration pour réimpression.
Lien d'origine: https://blog.csdn.net/sleepwalker_1992/article/details/82974703


2. Créer du stockage, stocker, demander

1. répertoire src:

Insérez la description de l'image ici
Remarque: la création de stockage est facultative, car j'ai encapsulé le stockage local (mise en cache) dans storage.js (le reste de cet article utilise js que j'ai encapsulé);Créer un magasin est nécessaire

2. Créer un stockage (facultatif)
// 封装操作localstorage本地存储的方法  模块化

var storage = {
    
    
    set(key, value) {
    
    
        localStorage.setItem(key, JSON.stringify(value));
        // localStorage.key = value;
        // localStorage[key] = value;
    },
    get(key) {
    
    
        return JSON.parse(localStorage.getItem(key));
    },
    getForIndex(index) {
    
    
        return localStorage.key(index);
    },
    getKeys(){
    
    
        let items = this.getAll();
        let keys = [];
        for (let index=0;index<items.length;index++){
    
    
            keys.push(items[index].key);
        }
        return keys;
    },
    getLength() {
    
    
        return localStorage.length;
    },
    getSupport() {
    
    
        return (typeof (Storage) !== "undefined") ? true : false;
    },
    remove(key) {
    
    
        localStorage.removeItem(key);
    },
    removeAll() {
    
    
        localStorage.clear();
    },
    getAll() {
    
    
        let len = localStorage.length;  // 获取长度
        let arr = new Array(); // 定义数据集
        for (var i = 0; i < len; i++) {
    
    
            // 获取key 索引从0开始
            var getKey = localStorage.key(i);
            // 获取key对应的值
            var getVal = localStorage.getItem(getKey);
            // 放进数组
            arr[i] = {
    
    
                'key': getKey,
                'val': getVal,
            }
        }
        return arr;
    }
}

export default storage;
3. Créez un magasin

import Vue from 'vue'
import Vuex from 'vuex'
import storage from '@/model/storage'

Vue.use(Vuex);
// 用Vuex.Store对象用来记录token
const store = new Vuex.Store({
    
    

  state: {
    
    
    // 存储token
    // token: storage.get('token') ? storage.get('token') : '',
    token:"",
    userName:"" // 可选
  },

  actions: {
    
    
    // removeToken: () => {
    
    
      // context.commit('set_token')
    // }
  },

  // 计算属性
  mutations: {
    
    
    // 修改token,并将token存入localStorage
    set_token(state,token) {
    
    
      state.token = token;
      storage.set('token', token);
      console.log('store、localstorage保存token成功!');
    },
    del_token(state) {
    
    
      state.token = "";
      storage.remove("token");
    },
    // 可选
    setUserInfo(state, userName) {
    
    
      state.userName = userName;
    }
  }
});

export default store;
4. Créer une demande
import axios from 'axios'
import store from '@/store'
import router from '@/router'

// create an axios instance
const service = axios.create({
    
    
    // index.js设置了代理(解决跨域) invoice = http://58.246.79.142:25005
    baseURL: "/invoice", // url = base url + request url
    timeout: 5000, // request timeout
   }

})

//添加请求拦截器,若token存在则在请求头中加token,不存在也继续请求
service.interceptors.request.use(
    config => {
    
    
        // 每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器,没有则不带token
        // Authorization是必须的
        if (store.state.token) {
    
    
            config.headers.Authorization = store.state.token;
        }
        return config;
    },
    error => {
    
    
        console.log("在request拦截器显示错误:", error.response)
        return Promise.reject(error);
    }
);

//respone拦截器
service.interceptors.response.use(
    response => {
    
    
        // 在status正确的情况下,code不正确则返回对应的错误信息(后台自定义为200是正确,并且将错误信息写在message),正确则返回响应
        return response.data.code == 200 ? response : Promise.reject(response.data.message);
    },
    error => {
    
     
        // 在status不正确的情况下,判别status状态码给出对应响应
        if (error.response) {
    
    
            console.log("在respone拦截器显示错误:", error.response)
            switch (error.response.status) {
    
    
                case 401:
                    //可能是token过期,清除它
                    // this.$store.commit("del_token"); 
                    store.commit("del_token");

                    router.replace({
    
     //跳转到登录页面
                        path: '/login',
                         // 将跳转的路由path作为参数,登录成功后跳转到该路由
                        query: {
    
     redirect: router.currentRoute.fullPath }
                    });
            }
        }
        return Promise.reject(error.response.data);
    }
);


export default service

3. Configurez le proxy, encapsulez le routeur, définissez la protection du routeur, importez le routeur et stockez-le dans main.js

Premièrement, configurez le proxy

Insérez la description de l'image ici

2. Encapsulez le routeur de routage et configurez la protection de routage
/* eslint-disable */
import Vue from 'vue'
import Router from 'vue-router'
import Main from '@/main/index'

import store from '@/store'
import storage from '@/model/storage'

Vue.use(Router)

const routes = [
  {
    
    
    path: '/',
    name: 'Main',
    redirect: '/login',
    // 某些页面规定必须登录后才能查看 ,可以在router中配置meta,将需要登录的requireAuth设为true,
    meta: {
    
    
      requireAuth: true,
    }
  },

  {
    
    
    path: '/login',
    component: () => import('@/views/login'),
  },

  {
    
    
    path: '/invoice',
    redirect: '/invoice',
    component: Main,
  },

    ]
  },
  {
    
    
    path: '*',
    component: Main
  }
]

const router = new Router({
    
     routes: routes })

// 设置路由守卫,在进页面之前,判断有token,才进入页面,否则返回登录页面
if (storage.get("token")) {
    
    
  store.commit("set_token", storage.get("token"));
}
router.beforeEach((to, from, next) => {
    
    
  // 判断要去的路由有没有requiresAuth
  // to.matched.some(r => r.meta.requireAuth) or to.meta.requiresAuth
  if (to.matched.some(r => r.meta.requireAuth)) {
    
    
    if (store.state.token) {
    
    
      next(); //有token,进行request请求,后台还会验证token
    } else {
    
    
      next({
    
    
        path: "/login",
        // 将刚刚要去的路由path(却无权限)作为参数,方便登录成功后直接跳转到该路由,这要进一步在登陆页面判断
        query: {
    
     redirect: to.fullPath }  
      });
    }
  } else {
    
    
    next(); //如果无需token,那么随它去吧
  }
});

export default router
3. Introduisez le routeur et stockez-le dans main.js
import Vue from 'vue'
import App from './App'
import router from './router'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'
import store from '@/store'

// 兼容ie
// import 'babel-polyfill';

Vue.use(ElementUI);
Vue.config.productionTip = false
// 定义vue属性,就可以全局使用this.$store
Vue.prototype.$store = store;

new Vue({
    
    
  el: '#app',
  router:router,
  components: {
    
     App },
  template: '<App/>'
})

Quatrièmement, l'utilisation réelle de la page de connexion

Ne donnez que la fonction d'exemple de soumission de formulaire et la dépendance js

import {
    
     postLogin } from "@/api/login";

submitForm(formName) {
    
    
      this.$refs[formName].validate(valid => {
    
    
        if (valid) {
    
    
          let that = this;
          // console.log('username',this.loginForm.username)
          // 通过校验规则后进入校验用户名密码是否正确
          // 没有后台接口可以自定义一个函数来模拟,替换postLogin
          postLogin(this.loginForm.username, this.loginForm.password)
            .then(res => {
    
    
              console.log(res);
              
               that.$store.commit("set_token", res.data.token);
               that.$store.commit("setUserInfo", res.data.account);

              this.$notify({
    
    
                title: "登录成功",
                type: "success",
                showClose: false,
                duration: 1000
              });
              setTimeout(() => {
    
    
                // 此时要判断/login后面的参数,若无参数,进入主页;
                this.$router.push("/index");
                // 若有参数则参数为未有权限的那个路由,跳转到那个路由
                // this.$router.push(***); -- 具体要自己在这实现
              }, 1000);
            })
            .catch(error => {
    
    
            // 错误分为 status-请求错误 和 code-账号密码错误
              this.$message.error(error);
              console.log(error);
            });
        } else {
    
    
        // 不符合前端校验
          this.$message.error('format error:'+error);
          console.log('format error:',error);
          return false;
        }
      });
    }

@ / Api / login dont dépend ce qui précède:

import request from '@/utils/request.js'  // 前面封装的request
// 在request中,设置了根路径/invoice,所以每一个请求都会自动在前面带上invoice;
// 由于在config中的index配置过了代理(监听)的路径也是/invoice,但凡遇到/invoice路径就会替换为target目标地址(后台接口根地址)
// 实现跨域,即不限于只能访问根路径为127.0.0.1下的地址
export function postLogin(account,password) {
    
    
    console.log(account,password)
    return request({
    
    
        url: '/login',
        method: 'post',
        params:{
    
    
        // 具体传参(键)要看后台要求
            account:account,
            password:password
        }
    })
}

Je suppose que tu aimes

Origine blog.csdn.net/GeniusXYT/article/details/104402757
conseillé
Classement