[权限]基于角色的静态模式
绝大多数,用户角色和功能固定时,推荐在这种方式。
开发简单,工作量少,可以快速交付。
1 前端
1. 登录
当用户登录时,将用户角色写入到vuex,保存当前用户角色信息。
# store/index.js
import {createStore} from 'vuex'
export default createStore({
state: {
token: localStorage.getItem('token') || '',
role: localStorage.getItem('role') || ''
},
getters: {},
mutations: {
login(state, {token, role}) {
state.token = token
state.role = role
localStorage.setItem('token', token)
localStorage.setItem('role', role)
}
},
actions: {},
modules: {}
})
# 登陆
const handleFinish = () => {
const login_info = {
token: '123',
role: formState.role
}
store.commit('login', login_info)
message.info(formState.user + "登陆成功")
router.replace({name: "admin"})
};
2.定义路由
定义路由时,基于 meta 来指定哪些角色的用户可以访问此路由。
# router/index.js
const routes = [
{
path: '/login',
name: 'login',
component: () => import('../views/LoginView.vue'),
meta: {is_menu: false}
}, {
path: '/admin',
name: 'admin',
component: () => import('../views/AdminView.vue'),
meta: {is_menu: false},
children:
[
{
path: 'user',
name: 'user',
component: () => import('../views/admin/UserView.vue'),
meta: {role: ['user'], is_menu: true, title: 'user'}
},
{
path: 'user2',
name: 'user2',
component: () => import('../views/admin/User2View.vue'),
meta: {role: ['admin'], is_menu: true, title: 'user2'}
},
{
path: 'all',
name: 'all',
component: () => import('../views/admin/AllView.vue'),
meta: {role: ['admin','user'], is_menu: true, title: 'all'}
}]
}]
3.路由导航守卫
用户访问页面时,在导航守卫中,进行判断,是否有权访问此路由。
- 有权,继续访问
- 无权,跳转登录页面
outer.beforeEach((to, from, next) => {
let roles = to.meta.role
if (roles) {
console.log(store.state.role)
// 在roles里找权限store.state.role,找不到返回-1
if (roles.indexOf(store.state.role) != -1) {
next()
} else {
next({name: "login"})
}
} else {
next()
}
})
4.菜单的加载
根据vuex中的角色,加载自己的路由,并添加在菜单中。
<template>
<a-layout>
<a-layout-sider :style="{ overflow: 'auto', height: '100vh', position: 'fixed', left: 0 }">
<div class="logo"/>
<a-menu theme="dark" mode="inline" v-model:selectedKeys="selectedKeys">
<a-menu-item :key="item" v-for="item in routerlist">
<user-outlined/>
<router-link :to="{name:item.name}">{{ item.meta.title }}</router-link>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout :style="{ marginLeft: '200px' }">
<a-layout-header :style="{ background: '#fff', padding: 0 }"/>
<a-layout-content :style="{ margin: '24px 16px 0', overflow: 'initial' }">
<div :style="{ padding: '24px', background: '#fff', textAlign: 'center' }">
<router-view/>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script setup>
import {
UserOutlined,
// VideoCameraOutlined,
} from '@ant-design/icons-vue';
import {computed, ref} from 'vue';
import {useRouter} from "vue-router";
import {useStore} from "vuex";
const router = useRouter()
const store = useStore()
const selectedKeys = ref(['1'])
const routerlist = computed(
() => {
return router.getRoutes().filter(item => {
if (item.meta.is_menu && item.meta.role.indexOf(store.state.role) != -1) {
return true
}
})
}
)
</script>
5.按钮控制&权限判断
2 后端
- 直接在业务视图中进行角色判断,符合角色才能访问否则返回无权访问。
- 在drf权限组件对请求进行判断,是否有有权访问。
setting设置权限信息
# admin/user代表用户的角色
# department-list 指department的群体的url_name
# department-detail 指department的单个的url_name
PERMISSION = {
'admin': {
'department-list': ['get', 'post'],
'department-detail': ['get', 'delete', 'put', 'patch']
},
'user': {
'department-list': ['get'],
'department-detail': ['get']
}
}
定义Authentication(会先走鉴权)
class User:
def __init__(self, role):
self.name = 'szw'
self.role = role
class DepartmentAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.query_params.get('token')
role = request.query_params.get('role')
if token and role:
# 此处非真实用户,传入一个对象而已
user = User(role)
return user, None
else:
raise exceptions.AuthenticationFailed("鉴权失败")
def authenticate_header(self, request):
return "API"
定义Permission
class DepartmentPermission(BasePermission):
message = '没有权限'
def has_permission(self, request, view):
try:
role = request.user.role
except Exception as e:
return False
# 从配置文件获取权限的所有信息
from django.conf import settings
permission_dict = settings.PERMISSION.get(role)
if not permission_dict:
return False
# 获取当前访问的url的name和请求方式
method = request.method.lower()
url_name = request.resolver_match.url_name
method_list = permission_dict.get(url_name)
if not method_list:
return False
if method not in method_list:
return False
return True
def has_object_permission(self, request, view, obj):
# 针对/department/<d>/ 操作
return True
定义View
class DepartmentSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
fields = "__all__"
class DepartmentView(ModelViewSet):
queryset = models.Department.objects.all()
serializer_class = DepartmentSerializer
permission_classes = [DepartmentPermission, ]
authentication_classes = [DepartmentAuthentication, ]