vboot框架 后台动态获取权限的实现方法
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 pid is null 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; } } }
三、前端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>
到此,用户的菜单权限、按钮权限基本就完成了,亲测可用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)