登錄模塊
需要做路由的守衛(wèi),有些模塊是需要被保護的,必須登錄才能訪問。 常見手法是給路由添加?meta:{ auth:true }?來做標(biāo)識抖剿,表示需要做認證。
// 路由守衛(wèi)router.beforeEach((to,from, next) => {
? ? // 判斷要進入的路由是否需要認證? ? if(to.meta.auth) {
? ? ? ? // 通過token令牌機制判斷是否已經(jīng)登錄? ? ? ? const token = localStorage.getItem('token');
? ? ? ? if (token) {
? ? ? ? ? ? next(); // 如果登錄則放行识窿,進入路由? ? ? ? } else {
? ? ? ? ? ? // 跳轉(zhuǎn)斩郎,并攜帶重定向地址? ? ? ? ? ? next({
? ? ? ? ? ? ? path: '/login',
? ? ? ? ? ? ? query: {
? ? ? ? ? ? ? ? ? redirect: to.path
? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? } else {
? ? ? ? // 不需要驗證的模塊,直接放行? ? ? ? next();
? ? }
});
在 Vuex 中存儲登錄狀態(tài)?isLogin
importVuefrom'vue'
importVuexfrom'vuex'
importuserfrom'./service/user'Vue.use(Vuex);
exportdefaultnewVuex.Store({state: {isLogin: localStorage.getItem('token') ?true:false},mutations: { setLoginState(state, bool) { state.isLogin = bool;// true 表示登錄喻频,false 表示注銷} },actions: { login({commit}, user) {// 發(fā)起登錄請求缩宜,請求都拆分出去 service 文件夾中// 使用 service 的請求方法user.login(user).then(res=>{// 從 res.data 中解構(gòu)數(shù)據(jù),code和tokenconst{ code, token } = res.data;if(code) {// 登錄成功甥温,修改Vuex中間的登錄狀態(tài)commit('setLoginState',true);// 緩存令牌 tokenlocalStorage.setItem("token", token); }returncode;// 返回code 給下一個 .then 使用}); }, logout({ commit }) {// 清除緩存localStorage.removeItem('token');// 重置狀態(tài)commit('setLoginState',false); } }});
service文件夾下的服務(wù)
// 返回一個 Promises 方便外面使用importaxiosfrom'axios'exportdefault{? ? login(user) {// 注意:請求地址最好是抽出去統(tǒng)一管理returnaxios.get('/api/login', {params: user? ? ? ? });? ? }}
登錄組件中提交事件處理過程
// 提交函數(shù)中, dispatch 是調(diào)用 actios 中的方法锻煌,在通過 commit 發(fā)送 mutations 方法修改數(shù)據(jù)// 注意:this.model 就是傳遞的數(shù)據(jù)this.$store.dispatch("login",this.model)? ? .then(code=>{if(code) {// 登錄成功后,重定向姻蚓,如果沒有則重定向到首頁constpath =this.$route.query.redirect ||'/';this.$router.push(path);? ? ? ? }? ? }).catch(error=>{// 有錯誤發(fā)生 或 登錄失敗consttoast =this.$createToast({time:2000,text: error.message || error.response.data.message ||"登錄失敗",type:"error"});? ? ? ? toast.show();? ? });
需要考慮的檢查點
如何守衛(wèi)路由
如何進行異步操作
如何保存登錄狀態(tài)
如何模擬接口
HTTP 攔截器
新建?interceptor.js?文件宋梧,用于攔截請求和響應(yīng)
// token 過期導(dǎo)致請求失敗的情況可能出現(xiàn)在項目的任何地方,可以通過響應(yīng)攔截統(tǒng)一處理// 攔截器的作用:是對接口做一層保護狰挡,表示所有的接口都會帶有令牌 token? // 可以查看 axios 的文檔 : http://www.axios-js.com/zh-cn/docs/constaxios =require('axios');exportdefaultfunction(vm){// HTTP 請求攔截器axios.interceptors.request.use(config=>{// 在發(fā)送請求之前做些什么// 獲取token, 并添加到 headers 請求頭中consttoken = localStorage.getItem('token');if(token) {? ? ? ? ? ? config.headers.token = token;? ? ? ? }returnconfig;? ? });// HTTP 響應(yīng)攔截器// 統(tǒng)一處理 401 狀態(tài)捂龄,token 過期的處理释涛,清除token跳轉(zhuǎn)login // 參數(shù) 1, 表示成功響應(yīng)axios.interceptors.response.use(null, err => {// 沒有登錄或令牌過期if(err.response.status ===401) {// 注銷跺讯,情況狀態(tài)和tokenvm.$store.dispatch("logout");// 跳轉(zhuǎn)的登錄頁vm.$storer.push('/login');// 注意: 這里的 vm 實例需要外部傳入}returnPromise.reject(err);? ? });}// 使用攔截器// 1. 引入攔截器文件importinterceptorfrom'./interceptor'// 執(zhí)行攔截器初始化interceptor(vm);
注銷
需要清除 token 緩存的兩種情況:
用戶主動注銷
token 過期
需要做的事情:
清空緩存
重置登錄狀態(tài)
methods: {? logout() {this.$route.dispatch('login');? }}
深入理解令牌機制
Bearer Token規(guī)范
概念: 描述在HTTP訪問OAuth2保護資源時如何使用令牌的規(guī)范
特點:令牌就是身份證枢贿,無需證明令牌的所有權(quán)
具體規(guī)定:在請求頭中定義Auuthorization:Bearer token
Json Web Token 規(guī)范?https://jwt.io
概念:令牌的具體定義方式
規(guī)定:令牌由三部分構(gòu)成 頭殉农、載荷刀脏、簽名
頭:包含加密算法、令牌類型等信息
載荷:包含用戶信息超凳、簽發(fā)時間和過期時間等信息
簽名:根據(jù)頭愈污、載荷及秘鑰加密得到的哈希串