You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 15:24:03