1. 登錄頁
- 文件目錄 src/view/login/index.vue
- 登錄方法
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
// 調用的是 store/modules/user.js 里的 login 方法
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' })
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
2. 登錄過程
(1) 首先會執行 user.js 里的 login 方法,
- user.js 在 src/store/moudules/user.js
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
// 這里執行的 login 方法是 api/user.js 中的方法
login({ username: username.trim(), password: password }).then(response => {
//****這一部分改成你自己的業務邏輯****//
const { data } = response
//********************************//
commit('SET_TOKEN', data)
setToken(data)
resolve()
}).catch(error => {
reject(error)
})
})
}
(2) 修改 api/user.js 中的 login 方法
// 修改為你自己的后台地址,可能會產生跨域問題,百度有很多解決方案
// 如果你后台是 spring 項目,可以直接在相應的 controller加 @CrossOrigin 注解即可
export function login(data) {
return request({
url: 'http://localhost:8800/login',
method: 'post',
data: data
})
}
- 登陸后,token 存儲到 cookie,以后發送請求會自動在請求頭中添加 token 如果要修改相關信息,在 src/utils/request.js 中修改,包括 定義請求成功的返回碼,token 相關的返回碼
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// 請求時間超過 5s 視為錯誤
timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// 請求前處理
if (store.getters.token) {
// 為請求頭添加 token
config.headers['RB-Token'] = getToken()
}
return config
},
error => {
// 錯誤處理
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* 如果您想獲取http信息(例如標題或狀態)
* 請返回響應=> 響應
*/
/**
* 通過自定義代碼確定請求狀態
* 這只是一個例子
* 您也可以通過HTTP狀態代碼來判斷狀態
*/
response => {
const res = response.data
// 如果自定義代碼不是 1000,則將其判斷為錯誤。
if (res.code !== 1000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 這里的返回碼根據自己的業務邏輯進行調整,例如 token 過期
if (res.code === 2555 || res.code === 2111 || res.code === 2444) {
// to re-login
MessageBox.confirm('登錄信息已過期,請重新登錄', '確認', {
confirmButtonText: '重新登錄',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
3. 授權過程
(1) 查看 permission.js 的執行流程
- 在登錄完成后,執行了 setToken 將 token 信息保存到了 cookie 中(如果不想保存到 cookie 可以看后文的修改方法)。然后跳轉到 '/' 路徑,當路由發生變化時,觸發了 permission.js 中的 beforeEach 方法。
- permission.js 目錄 src/store/modules/permission.js
- 主要是看 router.beforeEach方法
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
console.log(hasToken);
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// 這里調用 store/modules/user.js 中的 info 方法
// 同樣,這里的邏輯需要根據你自己的需要進行調整
//******************************************//
const res = await store.dispatch('user/getInfo')
const roles = res.roleArray;
//*******************************************//
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
(2) 獲取用戶信息
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
// 調用 api/user.js 中的 getInfo 方法
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('驗證失敗,請重新登錄')
}
// 獲取用戶的角色列表,用戶名和頭像
const roles = data.roleArray;
const name = data.username;
const avatar = data.avatar;
if (!roles || roles.length <= 0) {
reject('角色必須為一個非空數組')
}
commit('SET_ROLES', roles)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
resolve(data)
}).catch(error => {
reject(error)
})
})
4. 將 token 存儲到 localStorage
const TokenKey = 'RB-Token'
export function getToken() {
return localStorage.getItem(TokenKey);
}
export function setToken(token) {
return localStorage.setItem(TokenKey, token);
}
export function removeToken() {
return localStorage.removeItem(TokenKey);
}