一、目錄結(jié)構(gòu)
- assets放置了靜態(tài)文件
- components放置了通用組件
- config放置了一些常量配置
- helper放置了主要的功能模塊比如ajax.js、api.js
- mixins放置了混入
- router放置了路由文件
- store放置了vuex的文件
- views放置了頁面文件

二、 鑒權(quán)
項(xiàng)目的登陸狀態(tài)由Vuex+LocalStorage維持,項(xiàng)目的鑒權(quán)主要靠 路由鑒權(quán) 和 Ajax鑒權(quán)。
store結(jié)構(gòu)

state,localStorage維持了登陸信息的持久化
const state = {
userInfo: $storage.getLocalStorage('userInfo') || {}
}
設(shè)置和刪除userInfo的都放在mutation里
import { $storage } from '@/helper'
export default {
setUserInfo (state, info) {
state.userInfo = info
$storage.setLocalStorage('userInfo', info)
},
deleteUserInfo (state) {
state.userInfo = null
$storage.removeLocalStorage('userInfo')
}
}
向服務(wù)器獲取userInfo放在action里(異步類型的)
import { $apis } from '@/helper'
export default {
async getUserInfo ({ commit, state }) {
let userId = state.userInfo.id
if (userId) {
$apis.getUserInfo(userId).then(res => {
commit('setUserInfo', res)
})
}
}
}
auth文件
實(shí)際上router鑒定權(quán)限調(diào)用的都是這兩個(gè)方法,把它們分離出一個(gè)文件,用來檢查有沒有userInfo和userInfo是否是Admin的權(quán)限。
import { $apis, $storage } from '.'
export default {
checkSession () {
return $storage.getLocalStorage('userInfo') || false
},
async checkAdmin () {
let userInfo = $storage.getLocalStorage('userInfo') || {}
let userId = userInfo.id || 0
if (!userId) return false
userInfo = userInfo || (await $apis.getUserInfo(userId))
let isAdmin = userInfo.permission < 2
return userInfo.id && isAdmin
}
}
router結(jié)構(gòu)

鑒權(quán)這里用的是全局前置守衛(wèi),所以在beforeEachHooks.js寫上鑒定權(quán)限的規(guī)則。
規(guī)則:在需要admin權(quán)限的地方無權(quán)限訪問,則會(huì)跳到404頁面;在需要登陸權(quán)限的地方無權(quán)限訪問,則會(huì)跳到login界面。
import { $auth } from '@/helper'
export default {
checkVisitAuth (to, from, next) {
if (to.meta.isNeedAdmin) {
$auth.checkAdmin().then(result => {
return result ? next() : next({ path: '/404' })
})
} else if (to.meta.isNotNeedLogin) {
next()
} else {
$auth.checkSession() ? next() : next({ path: '/login' })
}
}
}
在index.js處掛載該規(guī)則
Object.values(beforeEachHooks).forEach(hook => {
routerInstance.beforeEach(hook)
})
Ajax
用了一層requestHandle來封裝 axios,以后可能會(huì)改用interceptors來定制,比較符合通用的做法。
后端返回 401 就是沒有登陸或者登陸信息過期,這時(shí)候清空登陸緩存狀態(tài),然后重定向到登陸頁面。
后端返回 403 就是沒有權(quán)限訪問,由于本項(xiàng)目403也是跳到404頁面所以和404同用一個(gè)處理方式。
后端返回 415 是訪問api過多被限制。
/**
* @param url
* @param method get|post|put|delete...
* @param params like queryString. if a url is index?a=1&b=2, params = {a: '1', b: '2'}
* @param data post data, use for method put|post
* @returns {Promise}
*/
function requestHandle (url, method, options) {
if (options !== undefined) {
var { params = {}, data = {} } = options
} else {
options = {}
}
return new Promise((resolve, reject) => {
axios({
url,
method,
params,
data
})
.then(
res => {
if (res.status === 200 || res.status === 201 || res.status === 204) {
resolve(res.data)
} else {
reject(res)
}
},
err => {
if (err.response.status === 401) {
store.commit('deleteUserInfo')
Vue.prototype.$error('請(qǐng)登陸')
window.location.href = '/login'
reject(err)
} else if (
err.response.status === 403 ||
err.response.status === 404
) {
reject(err.response.data)
} else if (err.response.status === 415) {
Vue.prototype.$error('您訪問太過頻繁, 已被限速')
reject(err.response.data)
}
}
)
.catch(err => {
Vue.prototype.$error(err)
reject(err)
})
})
}
總體結(jié)構(gòu)
實(shí)際上該項(xiàng)目的鑒權(quán)就是路由攔截那些正常的權(quán)限缺失,減少后端壓力,而在登陸信息過期或者惡意修改登陸信息的會(huì)遭到后端的鐵拳制裁??,后端必須要有完整的鑒權(quán)系統(tǒng)才能是健壯的。