- 首次登錄時,后端服務器判斷用戶賬號密碼正確之后,根據用戶id、用戶名、定義好的秘鑰、過期時間生成 token ,返回給前端;
- 前端拿到后端返回的 token ,存儲在 localStroage 和 Vuex 里;
- 前端每次路由跳轉,判斷 localStroage 有無 token ,沒有則跳轉到登錄頁,有則請求獲取用戶信息,改變登錄狀態;
- 每次請求接口,在 Axios 請求頭里攜帶 token;
- 后端接口判斷請求頭有無 token,沒有或者 token 過期,返回401;
- 前端得到 401 狀態碼,重定向到登錄頁面。
store.js
import Vue from 'vue' import Vuex from 'vuex' import VuexPersistence from 'vuex-persist' Vue.use(Vuex) const vuexLocal = new VuexPersistence({ storage: window.localStorage, reducer: state => ({ token: state.token, // 這個就是存入localStorage的值 WXTempKey: state.WXTempKey }) }) const store = new Vuex.Store({ state: { token: "", WXTempKey: '', isLogin: false, uid: 0, name: '', avatar: '' }, mutations: { setToken(state, token) { state.token = token }, setLogin(state, flag) { state.isLogin = flag }, setWXTempKey(state, WXTempKey) { state.WXTempKey = WXTempKey }, }, actions: {}, plugins: [vuexLocal.plugin] }) export default store
登陸頁
// 登陸方法 async login() { if (!this.phone || !this.password) { // this.$toasted.error("請輸入完善信息", { icon: "error" }).goAway(2000); Notify({ type: 'danger', message: "請輸入完善信息", duration: 1500 }) return; } try { // await等待一個異步返回的結果 如果沒有await 會報user is undefined 獲取不到 let res = await this.http.post("/api/TokenAuth/MemberAuthenticate", { Phone: this.phone, PhoneCode: this.password, WXTempKey: this.$store.state.WXTempKey ? this.$store.state.WXTempKey : "" }); console.log(res); if (res.Result) { // debugger // console.log(res); // localStorage.setItem("token","res.Result.AccessToken"); this.$store.commit("setToken", res.Result.AccessToken); Toast({ mask: false, message: '登錄成功', position: 'bottom' }); this.$router.replace({ name: "index" }); } else { // this.$toasted // .error(res.Error.Message, { icon: "error" }) // .goAway(2000); } } catch (error) { // this.$toasted.error(error.message, { icon: "error" }).goAway(2000); } }
http.js
import axios from 'axios' import store from './store' import { getToken } from '@/util/token' import qs from 'qs' import config from './config' import router from './router' import Vue from 'vue' import VuexPersistence from 'vuex-persist' import { Notify,Toast } from 'vant' console.log(config) // 創建axios實例 const http = axios.create({ baseURL: config.api_base, timeout: 15000, //設置請求頭 headers: { // 'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type' : 'application/json', }
//利用qs解析json數據讓后端可以解析
transformRequest: [
function(data, headers) {
data = data || {}
data = qs.stringify(data)
return data
}
]
}) // request攔截器 http.interceptors.request.use(config => { config.data = config.data ? config.data : {} config.headers["authorization"] =store.state.token; //把token添加到請求頭每次請求接口時候帶上
if(config.method=='get'){ Toast({ mask: false, message: '加載中...', position: 'bottom' }); }else{ Toast.loading({ mask: true, message: '加載中...', position: 'middle', loadingType:'spinner' }); } if (router.currentRoute && router.currentRoute.meta.requiresAuth) { if (localStorage.getItem('user')) { return Promise.reject('請登錄后操作') } else { // config.headers.Authorization = token; // config.headers['authorization'] = `${store.state.token}`; console.log('interceptors config=',config) return config } } else { return config } }) // respone攔截器 http.interceptors.response.use( response => { let data = response.data let msg = data.message || '' Toast.clear(); if (response.status === 200) { if (response.data.Result) { if (response.data.Result.Code && response.data.Result.Code !== 0) { Notify({ type: 'danger', message: response.data.Result.Message, duration: 1500 }) return Promise.resolve(response.data) } else { return Promise.resolve(response.data) } }else { return Promise.resolve(response.data) } } else { Notify({ type: 'danger', message: '請求失敗,請稍后再試!!!', duration: 1500 }) return Promise.reject(response) } // if (data.code == 401) { // // 賬號禁用 // Vue.toasted.error(data.message, { icon: 'error' }).goAway(2000) // router.replace({ name: 'login' }) // return Promise.reject(new Error(msg)) // } else if (data.code == 403) { // // 登錄失效 需重新登錄 // Vue.toasted.error('登錄失效 需重新登錄', { icon: 'error' }).goAway(2000) // router.replace({ name: 'login' }) // return Promise.reject(new Error(msg)) // } else if (data.code == 400) { // return Promise.reject(new Error(msg)) // } // return data }, err => { Toast.clear(); if (err.response.data.Error) { Notify({ type: 'danger', message: err.response.data.Error.Message, duration: 1500 }) if(err.response.status == 401 || (err.response.data.Error && err.response.data.Error.Code)){ console.log(router) store.commit("setToken", ''); router.push({ path: "/login", query:{ redirect:router.currentRoute.fullPath } }); } } else { Notify({ type: 'danger', message: '請求失敗!!!', duration: 1500 }) } return Promise.reject(err) } ) export default http