理清了整个的登录逻辑就能轻松的修改,登录逻辑参考:vue-element-admin登录逻辑,以及动态添加路由,显示侧边栏
结合项目实际而做
1. 角色的分配
除登录等基本页面,一共还有7个页面
共有三种角色:
- 超级管理员administrator:能够访问所有页面
- 管理员admin:能够访问管理员的三个页面和主页
- 代理agent:能够访问代理的三个页面和主页
管理员和代理都无法访问对方的页面
2. 登录逻辑
原本的逻辑是:点击按钮后触发点击事件 -> 事件中分发store.action -> action中调用axios接口 -> 成功后创建token。由于这个接口登录验证成功后直接返回用户的权限等信息,我们给它改成:点击按钮后触发点击事件 -> 事件中调用axios接口 -> 调用成功后分发store.action -> action中将用户信息用localStorage保存、根据role创建token保存到cookies中
3. 登录按钮的点击事件
接口是这样的:
\src\api\user.js
export function login(data) {
return request({
url: '接口地址',
method: 'get',
params: data
})
}
\src\views\login\index.vue:
引入接口login():
import { login } from "@api/user"
按钮点击事件handleLogin():
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
login({
userName: this.loginForm.username,
password: this.loginForm.password
}).then(response => {
if (response.data.error) {
this.$message.error(response.data.error);
} else {
this.$store.dispatch('user/login', response.data.user)
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
}
this.loading = false
})
.catch(() => {
this.loading = false
})
} else {
console.log('提交错误!')
return false
}
})
}
4. action
\src\store\modules\user.js
import { getToken, setToken, removeToken } from '@/utils/auth'
const actions = {
login({ commit }, userInfo) {
return new Promise((resolve, reject) => {
window.localStorage.setItem('userInfo', JSON.stringify(userinfo)); // 将用户信息存到localStorage中
var token;
// 根据接口返回的role创建相应的token
if(userInfo.role === '管理员') {
token = 'admin_token'
} else if (userInfo.role === '代理') {
token = 'agent_token'
} else {
token = 'administrator_token'
}
commit('SET_TOKEN', token)
setToken(token)
resolve()
)}
},
// 获取用户信息
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
var data = JSON.parse(window.localStorage.getItem('userInfo'))
if (!data) {
reject('验证失败,请重新登录!')
}
commit('SET_NAME', data.userName)
if (data.role === '管理员') {
commit('SET_ROLES', ['admin'])
} else if (data.role === '代理') {
commit('SET_ROLES', ['agent'])
} else {
commit('SET_ROLES', ['administrator'])
}
resolve(data)
})
},
// 用户登出:暂无登出接口,所以只执行清除token操作
logout({ commit, state, dispatch }) {
return new Promise((resolve, reject) => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resetRouter()
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
})
},
}
5. 按权限分配路由
\src\permission.js
NProgress.configure({ showSpinner: false }) // NProgress页面加载进度条:旋转效果关闭
const whiteList = ['/login', '/auth-redirect'] // 白名单
router.beforeEach(async(to, from, next) => {
// 开始进度条
NProgress.start()
// 设置页面标题
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// 如果是进入登录页面则不需要权限直接进入
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 {
await store.dispatch('user/getInfo')
// 从store中获取角色
var roles = store.getters.roles;
// 按照权限生成路由表
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()
}
}
})
6. 更改HTTP Status code判断
\src\utils\request.js
原本设定是当code不是20000则无法跳转,现根据实际需要修改
response => {
const res = response.data
// 当status返回为200时弹出错误提示
if (res.status !== 200) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
} else {
return res
}
},
后续可能还会有权限切换等问题将会根据进展再更新。