Asp.Net Core MVC如何用ActionFilterAttribute向布局传递登录用户角色ID
解决方案
方案1:通过全局ActionFilter实现ViewBag全局传值
步骤1:修改登录逻辑,持久化当前站点匹配的RoleId
你现有代码中获取到对应所选站点的RoleId后,仅通过路由参数传给首页,其他页面无法获取,需要先将值存入Session(或加密Cookie):
// 登录逻辑中匹配到正确RoleId的分支内 model.RoleId = query[i]; // 存入Session,也可以用加密Cookie替代 HttpContext.Session.SetString("CurrentSiteRoleId", query[i].ToString()); // 同时存所选站点Id,方便后续其他逻辑使用 HttpContext.Session.SetString("SelectedSiteId", model.sites); await signInManager.SignInAsync(user, false); return RedirectToAction("Index", "Home");
步骤2:实现自定义ActionFilter
创建SiteRoleFilter.cs类,继承ActionFilterAttribute,实现全局注入ViewBag逻辑:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; public class SiteRoleFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { // 仅处理用户已登录的场景 if (filterContext.HttpContext.User.Identity.IsAuthenticated) { // 从Session中取出当前站点的RoleId var roleId = filterContext.HttpContext.Session.GetString("CurrentSiteRoleId"); if (!string.IsNullOrEmpty(roleId)) { // 存入ViewBag,所有视图都可直接调用 filterContext.Controller.ViewBag.CurrentSiteRoleId = roleId; } } base.OnActionExecuting(filterContext); } }
步骤3:全局注册Filter
如果是.NET Core/.NET 5+,在Program.cs中添加注册:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<SiteRoleFilter>(); });
如果是.NET Framework,在FilterConfig.cs中注册:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new SiteRoleFilter()); }
步骤4:布局视图中调用
直接使用全局ViewBag的RoleId判断:
@if (signInManager.IsSignedIn(User) && ViewBag.CurrentSiteRoleId == "Admin对应的RoleId值" ) { Here it shows ManageUser option }
方案2:基于Identity Claims实现(更推荐)
该方案不需要依赖Session/Filter,直接利用ASP.NET Identity的身份凭证体系,原有视图判断逻辑可以基本不变:
步骤1:修改登录逻辑,注入当前站点的角色Claim
替换原有signInManager.SignInAsync的逻辑,手动生成只包含当前站点角色的身份凭证:
model.RoleId = query[i]; await signInManager.SignOutAsync(); // 获取用户原有Claims var claims = await userManager.GetClaimsAsync(user); // 移除原有所有角色Claim var roleClaims = claims.Where(c => c.Type == ClaimTypes.Role).ToList(); foreach (var claim in roleClaims) { await userManager.RemoveClaimAsync(user, claim); } // 添加当前站点匹配的角色Claim var roleName = await applicationUserManager.GetRoleNameByIdAsync(query[i]); // 自己实现根据RoleId查角色名的方法 await userManager.AddClaimAsync(user, new Claim(ClaimTypes.Role, roleName)); // 登录 await signInManager.SignInAsync(user, false); return RedirectToAction("Index", "Home");
步骤2:直接在布局视图使用原有判断
不需要修改任何视图代码,原有User.IsInRole("Admin")会自动读取当前站点的角色Claim,只会匹配当前所选站点的角色,完美解决多站点角色隔离问题。
原有代码问题修正
你原有登录逻辑中RedirectToAction("Index", "Home", query[i])是将RoleId作为路由参数传递,仅首页可以通过路由参数获取,其他页面无法访问到该值,这是你之前逻辑失效的核心原因。
内容的提问来源于stack exchange,提问作者r2000_na
相关产品推荐
相关产品推荐

