前言
对于不同权限的用户可以查看不同的页面,这种现象是非常常见的,这就不得不提起角色鉴权,如果不清楚什么是鉴权的友友们可以移步至文章 《登录鉴权机制详解:从前端到后端的全面解析》先了解一下,那么废话不多说我们直接进入主题!
正文
准备工作
这里我们创建一个ts项目
npm init vite
语言选择ts,框架依旧是vue.
这里为大家介绍一个全新的第三方库nprogress,这个库,可以让我们在加载页面的时候,会有一个和加载进度条的效果,非常的好用,使用起来也非常的简单,大家可以自行尝试下。
然后我们在终端中下载第三库pinia,vue-router
npm i vue-router
npm i pinia
我们先来处理中央数据库pinia部分,我们再src路径下创建一个store文件夹,这里我们实现一下不同的用户可以登录哪些页面.
第一步我们依旧是引入我们需要的方法
import {defineStore} from 'pinia'
import {ref} from 'vue'
然后再是创建一个仓库,用于存放数据,只不过这个数据不是一个单纯的数据,它可以明确指出,该用户可以进入哪些页面
const defaultList = {
admin: [
'0',
'1',
'11',
'12',
'13',
'2',
'21',
'22',
'23',
'24',
'25',
'26',
'27',
'28',
'29',
'291',
'292',
'3',
'31',
'32',
'33',
'34',
'4',
'41',
'42',
'5',
'7',
'6',
'61',
'62',
'63',
'64',
'65',
'66',
],
user: ['0', '1', '11', '12', '13'],
};
这里我们简单化一下,值区别于user以及admin两个用户,这里面的这些字符,就是代表着他们可以访问到哪些页面。
const username = localStorage.getItem('username')
const key = ref<string[]>([])
if(username){
key.value = (username == 'admin')?defaultList.admin:defaultList.user
}
这里我们获取到用户登录时存入到本地浏览器中的数据.我们创建一个响应式数组,且是string类型的数组,我们使用了ts的类型限制,所以我们的key中的数据必须是一个string类型的数组。我们对于我从本地浏览器获取到的字符进行判断,如果等于user那么,该用户可以访问的页面则是由defaultList.user决定,返回由defaultList.admin决定,然后通过三元运算符对key.value赋值。
函数handleSet根据不同的用户名,给key.value赋值,拿到不同的权限。
const handleSet = (val:string[])=>{
key.value = val
}
以后返回数据
return {
defaultList,
key:(username == 'admin')?defaultList.admin:defaultList.user,
handleSet
}
这样我们就大致写好了仓库,现在别忘了在配置文件中使用
import {createPinia} from 'pinia'
app.use(createPinia())
做完这些之后我们然后src目录下创建文件夹router来配置路由
引入
import {createRouter,createWebHistory,RouteRecordRaw} from 'vue-router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css'
import {usePermissStore} from '../store/permiss.ts'
然后写一些路由路径,这里我们给了一些路由数组中的meta一个叫permiss的key,那么这个key的值,表示,defaultList.admin或者defaultList.user这两个数组的元素谁包含这个permiss,就可以访问到这个页面,而noAuth:true值为true表示,不需要权限就可以访问,否则需要权限。
const routes :RouteRecordRaw[] = [
{
path:'/',
redirect:'/dashborad'
},
{
path:'/',
name:'home',
component:()=>import('../views/home.vue'),
children:[
{
path:'/dashborad',
name:'dashborad',
component: ()=>import('../views/dashborad.vue'),
meta:{
title:'首页',
noAuth:true
}
},
{
path:'/system-user',
name:'system-user',
component: ()=>import('../views/system-user.vue'),
meta:{
title:'用户管理',
permiss:'11'
}
},
{
path:'/table',
name:'basetable',
component: ()=>import('../views/basetable.vue'),
meta:{
title:'基础表格',
permiss:'31'
}
}
]
},
{
path:'/login',
component: ()=>import('../views/login.vue'),
meta:{
title:'登录',
noAuth:true
}
},
{
path:'/403',
component: ()=>import('../views/403.vue'),
meta:{
title:'403 Not Found',
noAuth:true
}
},
{
path:'/:path(.*)',
redirect:'/404'
}
]
const router = createRouter({
history:createWebHistory(),
routes
})
这里我们要看一下这个写法,同样是使用了ts中的类型限制,所以在routes中的元素必须是路由数组
const routes :RouteRecordRaw[] = []
在前面我提到了nprogress,它的使用方法时在前置路由中开始,在后置路由中结束,这里会为大家演示。
router.beforeEach((to,from,next)=>{
NProgress.start();
const role = localStorage.getItem('username');
const permissStore = usePermissStore()
if(to.meta.title){
document.title = to.meta.title as string
}
if(!role&&to.meta.noAuth !==true){
next('/login')
}
else if(
typeof to.meta.permiss =='string'
&& !permissStore.key.includes(to.meta.permiss)){
next('/403')
}else{
next()
}
next();
})
router.afterEach(()=>{
NProgress.done();
})
const role = localStorage.getItem('username');:表示用户是否登录了,如果登录了就可以在本地浏览器中找到username的值。
const permissStore = usePermissStore();实例化一个仓库。
if(!role&&to.meta.noAuth !==true){
next('/login')
}
这段代码表示,你当前没有登录到页面,且该页面是需要登录权限的,然后给你跳转到登录页面.
否则就是,你登陆了,然后检查您访问的页面是否有permiss这个key,且这个key的值是不是string
!permissStore.key.includes(to.meta.permiss)则表示,如果你的permiss正确的话,就会再判断,你访问的这个页面的permiss在你用户的权限中是否有,否则跳转。最后就是未登录且不需要登录的,要鉴权且有权限的。
nprogress在后置路由中结束
router.afterEach(()=>{
NProgress.done();
})
现在我们来看看login.vue中的逻辑实现,html部分我们就不展示了
const lgStr = localStorage.getItem('login-param');
const defParam = lgStr? JSON.parse(lgStr) : null
const param = reactive<LoginInfo>({
username: defParam? defParam.username : '',
password: defParam? defParam.password : ''
})
这里我们获取一下本地浏览器中的userinfo的数据,如果存在defParam的值就是本地浏览器中存入的数据,这表示用户已经登录过了,通过v-model绑定在表单的输入框中,表示,我们第一次登录成功后,不清除本地浏览器中的数据,当我们之后登录时,就不需要输入数据了。前提是我们要选中'记住密码'
当我们提交表单后,逻辑设定又是什么呢?
const submitForm = () => {
if (!login.value) return
// 严谨
login.value.validate(valid => {
console.log(valid);
if (valid) {
ElMessage.success('登录成功')
localStorage.setItem('username',param.username)
const keys = permissStore.defaultList[
param.username == 'admin'? 'admin' : 'user'
]
permissStore.handleSet(keys)
if (checked.value) {
localStorage.setItem(
'login-param',
JSON.stringify(param)
)
} else {
localStorage.removeItem('login-param')
}
router.push('/')
} else {
ElMessage.error('登录失败')
}
})
}
这里的validate 方法通常与表单验证相关联,特别是在使用了表单验证库的情况下。validate 方法用于验证表单中的输入字段是否符合预期的规则。
我们来看看这段代码
param.username == 'admin'? 'admin' : 'user'通过三元运算符,判断用户名是什么,如果是user就拿到permissStore.defaultList[value]中的值,也就是拿到了user的权限,并通过handleSet设置权限
那也就是意味着在路由中的
中的permissStore.key.includes(to.meta.permiss)的值,就是通过用户登录,调用函数handleSet设置的。
if (checked.value) {
localStorage.setItem(
'login-param',
JSON.stringify(param))
} else {
localStorage.removeItem('login-param')
}
这里实现的逻辑是当我们点击'记住密码'这个勾选框,就会把用户信息存入本利浏览器中,如果之前用户选择了'记住密码',但是现在不想选择'记住密码'了,点击勾选框,就会将该用户的信息从本地浏览器中移除。
现在我们来看看用户权限
user用户是不含31这个页面的权限的
那么换成admin就可以正常访问了
本文到此,用户角色鉴权的实现基本原理就介绍完了,感谢大家阅读!!若有不足恳请指出,谢谢大家!