欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

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

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

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

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

以基于 element 的管理后臺為例,在 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: [],
? ? // 自動權(quán)限相關(guān)
? ? group_id: 0,
? ? user_id: 0,
? ? menu_json: [], // 后端返回的權(quán)限Json儲存在這里
? ? 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) => {
? ? ? // 動態(tài)路由、動態(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
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? ? // 動態(tài)路由、動態(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)動態(tài)權(quán)限

在 Django 中利用 Permission 結(jié)合權(quán)限表,在每個接口在被調(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


# 最終動態(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('請求的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)動態(tài)菜單和動態(tài)權(quán)限的文章就介紹到這了,更多相關(guān)Django Vue 動態(tài)菜單和動態(tài)權(quán)限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論