vboot框架 後臺動態獲取許可權的實現方法
阿新 • • 發佈:2022-04-21
vboot框架 後臺動態獲取許可權的實現方法
前言:
以前用的框架總感覺有不舒服的地方,然後就一直在尋找一個理想的框架,研究了幾十個框架,vboot框架讓我眼前一亮,
上手後發現服務端許可權角色功能沒有實現,一度想拋棄,後來下決心費點功夫補充一下,沒辦法實在太喜歡這個框架了,
還有很多需要完善的地方,目前只實現了:使用者的角色許可權(選單許可權、按鈕許可權)的基本功能,其他的(部門許可權、崗位許可權、群組許可權)沒有實現
基本能滿足一般專案的要求
感謝框架的作者,也感謝我的好友“風清揚”給與的大力幫助,水平有限僅供參考,歡迎提出寶貴意見
相關文件:https://vvbin.cn/doc-next/guide/auth.html#%E5%90%8E%E5%8F%B0%E5%8A%A8%E6%80%81%E8%8E%B7%E5%8F%96
一、vboot-net後臺需要修改的幾個地方:
1、SysOrgUser.cs增加一個欄位
[SugarColumn(ColumnDescription = "系統管理員", DefaultValue="0", IsNullable = true)] public int AdminType { get; set; }
2、AdminType.cs 修改:普通賬號 None=0
public enum AdminType { /// <summary> /// 超級管理員 /// </summary> [Description("超級管理員")] SuperAdmin = 1, /// <summary> /// 管理員 /// </summary> [Description("管理員")] Admin = 2, /// <summary> /// 普通賬號 /// </summary> [Description("普通賬號")] None = 0 }
3、PubAuthInitService.cs
所有的comp = "/sys/org/dept/index.vue"去掉【.vue】,前端會自動補上.vue, 否則找不到頁面,如果資料庫已生成可直接改資料庫表的資料
二、vboot-net後臺
1、PubAuthApi.cs增加已下介面
[HttpGet("/getMenuList")] [AllowAnonymous] public async Task<dynamic> getMenuList() { //生成樹形選單 List<RouteItem> treelist = await _loginService.GetMenuList(_userManager.UserId, _userManager.User.AdminType); return treelist; } [HttpGet("/getPermCode")] [AllowAnonymous] public async Task<List<string>> getPermCode() { //按鈕許可權標識 List<string> permlist = await _loginService.GetPermCode(_userManager.UserId, _userManager.User.AdminType); return permlist; }
2、LoginService.cs的完整程式碼如下
using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Furion.DependencyInjection; using Furion.FriendlyException; using SqlSugar; using Vboot.Core.Common; using Vboot.Core.Module.Pub.Auth; using Vboot.Core.Module.Sys; namespace Vboot.Core.Module.Pub { public class LoginService : ITransient { private readonly ISqlSugarRepository<SysOrgUser> _repo; public LoginService(ISqlSugarRepository<SysOrgUser> repo) { _repo = repo; } public async Task<DbUser> getDbUser(string username) { const string sql = "select id,name,pacod,retag from sys_org_user where usnam=@username and avtag=1"; var dbUser = await _repo.Ado.SqlQuerySingleAsync<DbUser>(sql, new{username}); // if (dbUser == null) // { // throw new Exception("賬號不存在或密碼錯誤"); // } if (dbUser == null) { throw Oops.Oh(ErrorCode.D1000); } return dbUser; } /// <summary> /// 根據當前登入使用者生成選單樹 /// </summary> /// <param name="userid"></param> /// <param name="admintype"></param> /// <returns></returns> public async Task<List<RouteItem>> GetMenuList(string userid, int admintype) { List<RouteItem> rootList = await GetRootList(userid, admintype); List<RouteItem> routeList = await GetRouteList(userid, admintype); List<RouteItem> treelist = GetMenuTreeList(routeList, rootList); return treelist; } /// <summary> /// 獲取當前登入使用者的PermCode /// </summary> /// <param name="userid"></param> /// <param name="admintype"></param> /// <returns></returns> public async Task<List<string>> GetPermCode(string userid, int admintype) { List<string> perm = new List<string>(); string sql; if (admintype == (int)AdminType.SuperAdmin) { sql = $@"SELECT perm FROM sys_auth_menu WHERE `type`='B'"; } else { sql = $@"SELECT perm FROM sys_auth_menu WHERE `type`='B' AND shtag=1 AND avtag=1 AND id IN ( SELECT `mid` FROM sys_auth_role_menu a LEFT JOIN sys_auth_role_org b ON b.rid=a.rid WHERE b.oid='{userid}' )"; } List<SysAuthMenu> menulist = await _repo.Context.SqlQueryable<SysAuthMenu>(sql).ToListAsync(); for (int i = 0; i < menulist.Count; i++) { perm.Add(menulist[i].perm); } return perm; } /// <summary> /// 從資料庫獲取選單列表轉換成前端需要的格式 /// </summary> /// <param name="userid"></param> /// <param name="admintype"></param> /// <returns></returns> private async Task<List<RouteItem>> GetRouteList(string userid, int admintype) { string sql; if (admintype == (int)AdminType.SuperAdmin) { sql = $@"SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu where `type`!='B' ORDER BY ornum"; } else { sql = $@"SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu WHERE `type`!='B' AND shtag=1 AND avtag=1 and id IN ( SELECT a.mid FROM sys_auth_role_menu a LEFT JOIN sys_auth_role b ON b.id=a.rid LEFT JOIN sys_auth_role_org c ON c.rid=b.id WHERE c.oid='{userid}' ) ORDER BY ornum"; } List<RouteItem> routelist = await ToWebmenuList(sql); return routelist; } /// <summary> /// 取當前登入使用者許可權的根選單列表 /// </summary> /// <param name="userid"></param> /// <param name="admintype"></param> /// <returns></returns> private async Task<List<RouteItem>> GetRootList(string userid, int admintype) { string sql; if (admintype == (int)AdminType.SuperAdmin) { sql = $@"SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu WHERE isnull(pid)=true and `type`!='B' ORDER BY ornum"; } else { sql = $@"SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu WHERE id IN ( SELECT pid FROM ( SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu WHERE `type`!='B' AND shtag=1 AND avtag=1 and id IN ( SELECT a.mid FROM sys_auth_role_menu a LEFT JOIN sys_auth_role b ON b.id=a.rid LEFT JOIN sys_auth_role_org c ON c.rid=b.id WHERE c.oid='{userid}' ) ) a ) AND id NOT IN ( SELECT id FROM ( SELECT id,pid,ornum,`name`,icon,path,comp,`code`,redirect FROM sys_auth_menu WHERE `type`!='B' AND shtag=1 AND avtag=1 and id IN ( SELECT a.mid FROM sys_auth_role_menu a LEFT JOIN sys_auth_role b ON b.id=a.rid LEFT JOIN sys_auth_role_org c ON c.rid=b.id WHERE c.oid='{userid}' ) ) b ) ORDER BY ornum"; } List<RouteItem> rootlist = await ToWebmenuList(sql); return rootlist; } /// <summary> /// 取選單列表轉web端格式列表 /// </summary> /// <param name="sql"></param> /// <returns></returns> private async Task<List<RouteItem>> ToWebmenuList(string sql) { List<RouteItem> list = new List<RouteItem>(); var menulist = await _repo.Context .SqlQueryable<SysAuthMenu>(sql) .ToListAsync(); for (int i = 0; i < menulist.Count; i++) { RouteMeta meta = new RouteMeta(); meta.orderNo = menulist[i].ornum; meta.icon = menulist[i].icon; meta.title = menulist[i].name; RouteItem item = new RouteItem(); item.id = menulist[i].id; item.pid = menulist[i].pid; item.path = menulist[i].path; item.component = menulist[i].comp; //item.component = "/sys/auth/role/index"; item.name = menulist[i].code; item.redirect = menulist[i].redirect; item.meta = meta; item.children = new List<RouteItem>(); list.Add(item); } return list; } /// <summary> /// 生成樹形選單 /// </summary> /// <param name="menulist"></param> /// <param name="rootlist"></param> /// <returns></returns> private List<RouteItem> GetMenuTreeList(List<RouteItem> menulist, List<RouteItem> rootlist) { if (menulist == null) { menulist = new List<RouteItem>(); } List<RouteItem> treelist = new List<RouteItem>(); treelist.AddRange(rootlist); GetChildrenList(menulist, rootlist); return treelist; } /// <summary> /// 取子選單 /// </summary> /// <param name="menulist"></param> /// <param name="plist"></param> private void GetChildrenList(List<RouteItem> menulist, List<RouteItem> plist) { foreach (RouteItem item in plist) { List<RouteItem> childrenlist = menulist.Where(p => p.pid == item.id).ToList(); item.children.AddRange(childrenlist); GetChildrenList(menulist, childrenlist); } } } public class RouteMeta { public int? orderNo { get; set; } // title public string title { get; set; } //// dynamic router level. //public int? dynamicLevel{get;set;} //// dynamic router real route path (For performance). //public string realPath{get;set;} //// Whether to ignore permissions //public bool? ignoreAuth{get;set;} //// role info RoleEnum[] //public object roles { get; set; } //// Whether not to cache //ignoreKeepAlive?: boolean; //// Is it fixed on tab //affix?: boolean; //icon on tab public string icon { get; set; } //frameSrc?: string; //// current page transition //transitionName?: string; //// Whether the route has been dynamically added //hideBreadcrumb?: boolean; //// Hide submenu //hideChildrenInMenu?: boolean; //// Carrying parameters //carryParam?: boolean; //// Used internally to mark single-level menus //single?: boolean; //// Currently active menu //currentActiveMenu?: string; //// Never show in tab //hideTab?: boolean; //// Never show in menu //hideMenu?: boolean; //isLink?: boolean; //// only build for Menu //ignoreRoute?: boolean; //// Hide path for children //hidePathForChildren?: boolean; } public class RouteItem { public string id { get; set; } public string pid { get; set; } public string path { get; set; } // component: any; public object component { get; set; } public RouteMeta meta { get; set; } public string name { get; set; } //alias?: string | string[]; public string redirect { get; set; } //public bool? caseSensitive{get;set;} public List<RouteItem> children { get; set; } } }LoginService.cs
三、前端vboot-vben
1、projectSetting.ts 許可權模式改為 BACK
模式
// Permission mode //permissionMode: PermissionModeEnum.ROUTE_MAPPING, permissionMode: PermissionModeEnum.BACK,
2、BACK模式下預設訪問views路徑不是pages路徑,所以要把pages下相應的目錄及檔案要拷貝到views下,如下圖所示:
3、前端按鈕許可權的實現 v-auth="'許可權標識'"
<vxe-button v-auth="'dept:delete'" @click="deleteEvent($refs.xGrid)">刪 除</vxe-button>
到此,使用者的選單許可權、按鈕許可權基本就完成了,親測可用