[权限]基于角色的静态模式

绝大多数,用户角色和功能固定时,推荐在这种方式。
开发简单,工作量少,可以快速交付。

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, ]

后端代码

posted @ 2023-04-08 18:09  Sherwin_szw  阅读(12)  评论(0编辑  收藏  举报