深入Vue後臺管理開發之登入驗證

MrNow發表於2019-05-06

1.登入方法

1.1 傳統身份驗證的方法

  1. 使用者提交登入資訊
  2. 服務端生成一條記錄,其中會說明使用者資訊
  3. 服務端返回記錄的ID號給客戶端
  4. 這個ID號會被儲存在客戶端的Cookie裡,下次使用者再向服務端傳送請求時可以帶著這個Cookie,這樣服務端會驗證該Cookie裡的資訊,如果找到對應的記錄,說明使用者通過了身份驗證,就把使用者請求的資料返回給客戶端
  5. 而上面再服務端生成的就是使用者的Session,需要再服務端定期清理過期的Session

1.2 基於 token 的登入流程

  1. 客戶端使用使用者名稱跟密碼請求登入
  2. 服務端收到請求,去驗證使用者名稱與密碼
  3. 驗證成功後,服務端會簽發一個Token,再把這個Token傳送給客戶端
  4. 客戶端收到Token以後可以把它儲存起來,比如放在Cookie裡或者Local Storage
  5. 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的Token
  6. 服務端收到請求,然後去驗證客戶端請求裡面帶著的Token,如果驗證成功,就向客戶端返回請求的資料

1.3 token 作用

  • token存入本地cookie中,可以保證每次重新整理時使用者登入狀態不丟失
  • 通過token,還可以獲取到使用者的其他資訊

2. 邏輯程式碼

2.1. 登入事件

點選`handleLogin`觸發`vuex`中`actions`的`Login`派發行為
複製程式碼
handleLogin() {
      this.$store
          .dispatch('Login', this.loginForm)
          .then(() => {
            this.$router.push({ path: '/' });
          })
          .catch(() => {
            
          })
    }
複製程式碼

2.2. store.js

然後回到vuex,這裡的store.js改成store資料夾,分模組管理vuex

// 資料夾結構
|-- store
  |-- modules
  |-- getters.js
  |-- index.js
複製程式碼

我們劃分出,app, user 兩個模組,在 user 裡控制使用者的登入資訊,app 中儲存應用的狀態,如全域性loading或者控制第三方元件的全域性大小,如element-ui中的全域性元件size

// index.vue
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import getters from './getters'

Vue.use(Vuex)
const store = new Vuex.Store({
  modules: {
    user
  },
  getters
})

export default store
複製程式碼

user.js中儲存了登入事件所需的事件和資料,handleLogin事件觸發的是modulesuser模組的actions,這裡user.js中的具體方法和state資料,均是封裝過的

2.3 request 請求封裝

  1. utils/auth.js中封裝設定cookie的方法
// 匯入 Cookies
import Cookies from 'js-cookie'

// 設定 cookie name
const TokenKey = 'Admin-Token'

// 獲取 Admin-Token 的 cookie
export function getToken() {
  return Cookies.get(TokenKey);
}

// setToken 
export function setToken(token) {
  return Cookies.set(TokenKey, token);
}

// 移除 token
export function removeToken() {
  return Cookies.remove(TokenKey)
}
複製程式碼
  1. utils/request中封裝axios請求設定
import axios from 'axios'
import store from '../store'
import { getToken } from '@/utils/auth'

const service = axios.create({
  baseURL: 'http://193.112.153.155:3001',
  timeout: 5000  // 請求超時時間
})
export default service
複製程式碼
  1. 在api/login.js中封裝登入api請求
import request from '@/utils/request'

export function login(username, password) {
  return request({
    url: '/user/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}

export function getInfo(token) {
  return request({
    url: '/user/info',
    method: 'get',
    params: { token }
  })
}

export function logout() {
  return request({
    url: '/user/logout',
    method: 'post'
  })
}
複製程式碼
  1. 再回到modules/user.js中完成登入的store
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'

const user = {
  state: {
    token: getToken(),
    name: '',
    avatar: '',
    roles: []
  },

  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    }
  },

  actions: {
    // 登入
    Login({ commit }, userInfo) {
      const username = userInfo.username.trim()
      return new Promise((resolve, reject) => {
        login(username, userInfo.password).then(response => {
          const data = response.data;
          setToken(data.token)
          commit('SET_TOKEN', data.token);
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 獲取使用者資訊
    GetInfo({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo(state.token).then(response => {
          const data = response.data
          if (data.roles && data.roles.length > 0) { // 驗證返回的roles是否是一個非空陣列
            commit('SET_ROLES', data.roles)
          } else {
            reject('getInfo: roles must be a non-null array !')
          }
          commit('SET_NAME', data.name)
          commit('SET_AVATAR', data.avatar)
          resolve(response)
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 登出
    LogOut({ commit, state }) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          removeToken()
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 前端 登出
    FedLogOut({ commit }) {
      return new Promise(resolve => {
        commit('SET_TOKEN', '')
        removeToken()
        resolve()
      })
    }
  }
}

export default user
複製程式碼

本文僅供個人學習總結使用 參考:

vue+axios 實現登入攔截許可權驗證

手摸手,帶你用vue擼後臺 系列二(登入許可權篇) )

相關文章