亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Django Vue實(shí)現(xiàn)動(dòng)態(tài)菜單和動(dòng)態(tài)權(quán)限

 更新時(shí)間:2022年06月28日 10:15:28   作者:haeasringnar  
本文主要介紹了Django Vue實(shí)現(xiàn)動(dòng)態(tài)菜單和動(dòng)態(tài)權(quán)限,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

隨著前后端分離架構(gòu)的流行,在 web 應(yīng)用中,RESTful API 幾乎已經(jīng)成為了開發(fā)者主要選擇,它使得客戶端和服務(wù)端不需要保存對(duì)方的詳細(xì)信息,也就是無狀態(tài)性,但是這樣在項(xiàng)目中需要?jiǎng)討B(tài)菜單和動(dòng)態(tài)權(quán)限就困難起來,本場Chat就是為大家提供一種思路來解決實(shí)際項(xiàng)目中如何實(shí)現(xiàn)動(dòng)態(tài)菜單和權(quán)限。

因?yàn)?RESTful API 通常是無狀態(tài)性,服務(wù)器怎么樣才能知道用戶已經(jīng)登錄呢?這個(gè)時(shí)候常用的做法就是每個(gè)請(qǐng)求都會(huì)攜帶一個(gè) access token 來在服務(wù)端認(rèn)證用戶。最常用的就是 JWT 了,有感興趣的小伙伴可以再做深入學(xué)習(xí)。通俗來講,使用了 JWT 用戶在每次請(qǐng)求時(shí)都會(huì)在請(qǐng)求頭中攜帶一個(gè) Token ,服務(wù)端會(huì)在執(zhí)行操作之前先解析這個(gè) Token 進(jìn)行認(rèn)證,認(rèn)證完成之后服務(wù)端就會(huì)知道過來請(qǐng)求的用戶詳情,從而做出需要的返回。

用戶與用戶組的架構(gòu)設(shè)計(jì)

通常在一個(gè) web 應(yīng)用設(shè)計(jì)中,首先都是從用戶、用戶組開始的。用戶就是 web 應(yīng)用的核心,JWT 認(rèn)證也是因?yàn)橛脩舨糯嬖诘?。用戶在使?MySQL 的 web 應(yīng)用中就是一張用戶表,每一個(gè)用戶就是用戶表中的一條數(shù)據(jù)。用戶組就相當(dāng)于是用戶的權(quán)限了,例如 一般的系統(tǒng)中都會(huì)有超級(jí)管理員、管理員、普通用戶等用戶,用戶就是這些用戶組下的集合,那么用戶組和用戶就是一對(duì)多的關(guān)系,或者說每個(gè)用戶都有一個(gè)外鍵指向某個(gè)用戶組 ID。當(dāng)某個(gè)用戶是管理員時(shí)就表示他擁有管理員用戶組下的所有權(quán)限。

在這樣用戶組-用戶的架構(gòu)設(shè)計(jì)下,如何設(shè)計(jì)權(quán)限和菜單呢?首先,菜單就類似是用戶操作的一些功能的集合,集合內(nèi)的每個(gè)元素就相當(dāng)于是權(quán)限了。例如有個(gè)菜單名為 員工管理 ,在它下面就存在四個(gè)基本權(quán)限:查看員工、新增員工、編輯員工、刪除員工。也就是說把這四個(gè)權(quán)限想象成四個(gè)方法或功能,這些功能是關(guān)聯(lián)某個(gè)用戶組還是某個(gè)用戶呢?顯然是關(guān)聯(lián)某個(gè)用戶組是比較好的選擇。因?yàn)檫@樣用戶組可以攜帶著很多菜單以及菜單的權(quán)限,當(dāng)多個(gè)用戶屬于這個(gè)用戶組時(shí),這些用戶就擁有了該用戶組下的所有權(quán)限。否則關(guān)聯(lián)某個(gè)用戶的話,每個(gè)用戶在新增的時(shí)候都需要設(shè)置菜單和權(quán)限的話,不僅浪費(fèi)時(shí)間,還浪費(fèi)資源 占有數(shù)據(jù)庫空間。

用 RESTful API 的做法就是:用戶組的菜單和權(quán)限會(huì)作為記錄存放在權(quán)限表中,當(dāng)需要的時(shí)候服務(wù)端會(huì)將這些數(shù)據(jù)轉(zhuǎn)成 Json 返回給客戶端使用,當(dāng)然在服務(wù)端需要使用權(quán)限的接口也會(huì)使用權(quán)限表中的數(shù)據(jù)來判斷,請(qǐng)求接口的用戶是否有權(quán)限操作,根據(jù)權(quán)限表數(shù)據(jù)做不同處理。

動(dòng)態(tài)菜單和權(quán)限的設(shè)計(jì)思路與實(shí)現(xiàn)

那么動(dòng)態(tài)菜單和權(quán)限在服務(wù)端和客戶端究竟怎樣完成這些交互的呢?

  • 用戶登錄系統(tǒng)時(shí)輸入用戶名、密碼等進(jìn)行登錄,登錄成功之后會(huì)將該用戶的 Token 返回給用戶。
  • 用戶攜帶著這個(gè) Token 請(qǐng)求服務(wù)端的一個(gè)獲取用戶詳細(xì)信息接口,服務(wù)端在認(rèn)證通過后就將該用戶的用戶信息、用戶組信息以及用戶組的權(quán)限信息全部返回,此時(shí)客戶端用戶就得到了權(quán)限表的 Json 數(shù)據(jù),根據(jù)這些數(shù)據(jù)客戶端會(huì)展示不同的菜單項(xiàng)。
  • 客戶端在收到權(quán)限 Json 數(shù)據(jù)時(shí),根據(jù)權(quán)限中的菜單項(xiàng)設(shè)置,動(dòng)態(tài)的設(shè)置前端菜單。做到不同的用戶顯示不同的菜單項(xiàng)。
  • 當(dāng)用戶在請(qǐng)求其他接口時(shí),服務(wù)端會(huì)先進(jìn)行用戶認(rèn)證,在得到當(dāng)前請(qǐng)求用戶的同時(shí) 也會(huì)得到該用戶的用戶組,從而得到該用戶的所有權(quán)限信息。然后服務(wù)端會(huì)根據(jù)接口對(duì)應(yīng)的權(quán)限詳情做不同的處理,最終再返回給用戶相應(yīng)信息。例如 當(dāng)查到該用戶對(duì)當(dāng)前接口只有查看權(quán)限時(shí),如果用戶發(fā)起的是 POST 請(qǐng)求想新增數(shù)據(jù),那會(huì)服務(wù)端會(huì)直接返回 沒有執(zhí)行該操作的權(quán)限。

Vue 端如何實(shí)現(xiàn)動(dòng)態(tài)路由

以基于 element 的管理后臺(tái)為例,在 Vue 里面利用 VueX 狀態(tài)管理器,當(dāng)用戶登錄成功后,去獲取用戶詳細(xì)信息,獲取到詳細(xì)信息后根據(jù)權(quán)限 Json 數(shù)據(jù),在 Store 中將路由重新設(shè)置,不該展示路由節(jié)點(diǎn)的需要隱藏或刪除掉。從而做到不同的用戶展示不同的菜單。

Vue 端實(shí)現(xiàn)代碼示例

import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import router from '../../router'

const user = {
? state: {
? ? token: getToken(),
? ? name: '',
? ? avatar: '',
? ? roles: [],
? ? // 自動(dòng)權(quán)限相關(guān)
? ? group_id: 0,
? ? user_id: 0,
? ? menu_json: [], // 后端返回的權(quán)限Json儲(chǔ)存在這里
? ? router: router // 引入路由菜單
? },

? mutations: {
? ? SET_TOKEN: (state, token) => {
? ? ? state.token = token
? ? },
? ? SET_NAME: (state, name) => {
? ? ? state.name = name
? ? },
? ? SET_ROLES: (state, roles) => {
? ? ? state.roles = roles
? ? },
? ? SET_MENUS: (state, menus) => {
? ? ? state.menu_json = menus
? ? },
? ? SET_GROUP: (state, group_id) => {
? ? ? state.group_id = group_id
? ? },
? ? SET_USER: (state, user_id) => {
? ? ? state.user_id = user_id
? ? },
? ? SET_ROUTE: (state, router) => {
? ? ? // 動(dòng)態(tài)路由、動(dòng)態(tài)菜單
? ? ? console.log('router:', router.options.routes)
? ? ? var group_id = localStorage.getItem('ShopGroupId')
? ? ? var menus = JSON.parse(localStorage.getItem('ShopMenus'))
? ? ? console.log('group_id:', localStorage.getItem('ShopGroupId'))
? ? ? console.log('menus:', JSON.parse(localStorage.getItem('ShopMenus')))
? ? ? console.log('group_id為1,不執(zhí)行設(shè)置router操作')
? ? ? if (group_id !== '1') {
? ? ? ? for (var i in router.options.routes) {
? ? ? ? ? if (router.options.routes[i].children !== undefined) {
? ? ? ? ? ? for (var j in router.options.routes[i].children) {
? ? ? ? ? ? ? if (router.options.routes[i].children[j].path !== 'dashboard') {
? ? ? ? ? ? ? ? router.options.routes[i].children[j].hidden = true
? ? ? ? ? ? ? ? for (var k in menus) {
? ? ? ? ? ? ? ? ? if (menus[k].object_name == router.options.routes[i].children[j].name) {
? ? ? ? ? ? ? ? ? ? if (menus[k].menu_list) {
? ? ? ? ? ? ? ? ? ? ? router.options.routes[i].children[j].hidden = false
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? ? for (var i in router.options.routes) {
? ? ? ? if (router.options.routes[i].children !== undefined) {
? ? ? ? ? var len_router = router.options.routes[i].children.length
? ? ? ? ? var check_len = 0
? ? ? ? ? for (var j in router.options.routes[i].children) {
? ? ? ? ? ? if (router.options.routes[i].children[j].path !== 'dashboard') {
? ? ? ? ? ? ? if (router.options.routes[i].children[j].hidden !== null && router.options.routes[i].children[j].hidden !== undefined && router.options.routes[i].children[j].hidden === true) {
? ? ? ? ? ? ? ? check_len += 1
? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? if (len_router === check_len) {
? ? ? ? ? ? router.options.routes[i].hidden = true
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? ? // 動(dòng)態(tài)路由、動(dòng)態(tài)菜單的結(jié)束
? ? ? state.router = router
? ? }
? },

? actions: {
? ? // 登錄
? ? Login({ commit }, userInfo) {
? ? ? return new Promise((resolve, reject) => {
? ? ? ? login(userInfo).then(response => {
? ? ? ? ? const data = response.data
? ? ? ? ? setToken(data.token)
? ? ? ? ? commit('SET_TOKEN', data.token)
? ? ? ? ? resolve()
? ? ? ? }).catch(error => {
? ? ? ? ? reject(error)
? ? ? ? ? alert(error)
? ? ? ? })
? ? ? })
? ? },

? ? // 獲取用戶信息
? ? GetInfo({ commit, state }) {
? ? ? return new Promise((resolve, reject) => {
? ? ? ? getInfo().then(response => {
? ? ? ? ? const data = response.data
? ? ? ? ? console.log(data)
? ? ? ? ? commit('SET_NAME', data.username)
? ? ? ? ? commit('SET_ROLES', [data.group.en_name])
? ? ? ? ? commit('SET_MENUS', data.group.back_menu) // 將返回的權(quán)限數(shù)據(jù)保存
? ? ? ? ? commit('SET_GROUP', data.group.id)
? ? ? ? ? commit('SET_USER', data.id)
? ? ? ? ? localStorage.setItem('ShopMenus', JSON.stringify(data.group.back_menu))
? ? ? ? ? localStorage.setItem('ShopGroupId', data.group.id)
? ? ? ? ? commit('SET_ROUTE', router)
? ? ? ? ? resolve(response)
? ? ? ? }).catch(error => {
? ? ? ? ? reject(error)
? ? ? ? })
? ? ? })
? ? },

? ? // 前端 登出
? ? FedLogOut({ commit }) {
? ? ? return new Promise(resolve => {
? ? ? ? commit('SET_TOKEN', '')
? ? ? ? removeToken()
? ? ? ? resolve()
? ? ? })
? ? }
? }
}

export default user

Django 端如何實(shí)現(xiàn)動(dòng)態(tài)權(quán)限

在 Django 中利用 Permission 結(jié)合權(quán)限表,在每個(gè)接口在被調(diào)用之前先根據(jù)權(quán)限判斷,調(diào)用接口的用戶是否有權(quán)限操作,如果有就繼續(xù)完成后面的操作,否則直返返回 無權(quán)操作 的提示語。

Django 端代碼示例如下

from rest_framework import permissions
from rest_framework.permissions import DjangoModelPermissions, IsAdminUser
from rest_framework.permissions import BasePermission as BPermission
from shiyouAuth.models import GroupMenu


# 最終動(dòng)態(tài)權(quán)限類
class BasePermission(object):

? ? def base_permission_check(self, basename):
? ? ? ? # 權(quán)限白名單
? ? ? ? if basename in ['userinfo', 'permissions', 'login', 'confdict']:
? ? ? ? ? ? return True
? ? ? ? else:
? ? ? ? ? ? return False

? ? def has_permission(self, request, view):
? ? ? ? print('請(qǐng)求的path:', request.path.split('/')[1])
? ? ? ? basename = request.path.split('/')[1]
? ? ? ? if self.base_permission_check(basename):
? ? ? ? ? ? return True
? ? ? ? admin_menu = GroupMenu.objects.filter(object_name=basename).first()
? ? ? ? if admin_menu is None and request.user.group.id != 1:
? ? ? ? ? ? return False
? ? ? ? if request.user.group.id == 1:
? ? ? ? ? ? return True
? ? ? ? if view.action == 'list' or view.action == 'retrieve':
? ? ? ? ? ? # 查看權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_list == True)
? ? ? ? elif view.action == 'create':
? ? ? ? ? ? # 創(chuàng)建權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_create == True)
? ? ? ? elif view.action == 'update' or view.action == 'partial_update':
? ? ? ? ? ? # 修改權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_update == True)
? ? ? ? elif view.action == 'destroy':
? ? ? ? ? ? # 刪除權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_destroy == True)
? ? ? ? else:
? ? ? ? ? ? return False

? ? def has_object_permission(self, request, view, obj):
? ? ? ? basename = request.path.split('/')[1]
? ? ? ? if self.base_permission_check(basename):
? ? ? ? ? ? return True
? ? ? ? admin_menu = GroupMenu.objects.filter(object_name=basename).first()
? ? ? ? if admin_menu is None and request.user.group.id != 1:
? ? ? ? ? ? return False
? ? ? ? if request.user.group.id == 1:
? ? ? ? ? ? return True
? ? ? ? if view.action == 'list' or view.action == 'retrieve':
? ? ? ? ? ? # 查看權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_list == True)
? ? ? ? elif view.action == 'create':
? ? ? ? ? ? # 創(chuàng)建權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_create == True)
? ? ? ? elif view.action == 'update' or view.action == 'partial_update':
? ? ? ? ? ? # 修改權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_update == True)
? ? ? ? elif view.action == 'destroy':
? ? ? ? ? ? # 刪除權(quán)限
? ? ? ? ? ? return bool(request.auth and admin_menu.menu_destroy == True)
? ? ? ? else:
? ? ? ? ? ? return False

到此這篇關(guān)于Django Vue實(shí)現(xiàn)動(dòng)態(tài)菜單和動(dòng)態(tài)權(quán)限的文章就介紹到這了,更多相關(guān)Django Vue 動(dòng)態(tài)菜單和動(dòng)態(tài)權(quán)限內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue3中Provide和Inject的用法及工作原理詳解

    Vue3中Provide和Inject的用法及工作原理詳解

    在Vue 3中,Provide和Inject是一對(duì)用于組件間數(shù)據(jù)傳遞的API,通常用于父組件向其子組件傳遞數(shù)據(jù),但并不通過props的方式,本文將深入探討Provide和Inject的工作原理,并通過示例代碼幫助你理解如何在你的Vue應(yīng)用中使用它們,需要的朋友可以參考下
    2025-02-02
  • vue-router動(dòng)態(tài)設(shè)置頁面title的實(shí)例講解

    vue-router動(dòng)態(tài)設(shè)置頁面title的實(shí)例講解

    今天小編就為大家分享一篇vue-router動(dòng)態(tài)設(shè)置頁面title的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • vue3應(yīng)用elementPlus table并滾動(dòng)顯示問題

    vue3應(yīng)用elementPlus table并滾動(dòng)顯示問題

    這篇文章主要介紹了vue3應(yīng)用elementPlus table并滾動(dòng)顯示問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 一篇看懂vuejs的狀態(tài)管理神器 vuex狀態(tài)管理模式

    一篇看懂vuejs的狀態(tài)管理神器 vuex狀態(tài)管理模式

    一篇看懂vuejs的狀態(tài)管理神器,Vuex一個(gè)專為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • nginx部署訪問vue-cli搭建的項(xiàng)目的方法

    nginx部署訪問vue-cli搭建的項(xiàng)目的方法

    本篇文章主要介紹了nginx部署訪問vue-cli搭建的項(xiàng)目的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-02-02
  • Vue的transition-group與Virtual Dom Diff算法的使用

    Vue的transition-group與Virtual Dom Diff算法的使用

    這篇文章主要介紹了Vue的transition-group與Virtual Dom Diff算法的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • vue使用fengMap速度慢的原因分析

    vue使用fengMap速度慢的原因分析

    這篇文章主要介紹了vue使用fengMap速度慢的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 解決Vue + Echarts 使用markLine標(biāo)線(precision精度問題)

    解決Vue + Echarts 使用markLine標(biāo)線(precision精度問題)

    這篇文章主要介紹了解決Vue + Echarts 使用markLine標(biāo)線(precision精度問題),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Vue3 響應(yīng)式數(shù)據(jù) reactive使用方法

    Vue3 響應(yīng)式數(shù)據(jù) reactive使用方法

    這篇文章主要介紹了Vue3 響應(yīng)式數(shù)據(jù) reactive使用方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-11-11
  • Echarts實(shí)現(xiàn)一張圖現(xiàn)切換不同的X軸(實(shí)例代碼)

    Echarts實(shí)現(xiàn)一張圖現(xiàn)切換不同的X軸(實(shí)例代碼)

    這篇文章主要介紹了Echarts 如何實(shí)現(xiàn)一張圖現(xiàn)切換不同的X軸,通過動(dòng)圖給大家展示效果,實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-11-11

最新評(píng)論