ASP.Net Core 6 - 授权角色不起作用

问题描述 投票:0回答:5

我阅读了无数的教程、文章和问题。

我不明白为什么

[Authorize(Roles = "SuperAdmin")]
或任何其他角色不起作用。无论指定的角色如何,每个人都会收到 403:

//[Authorize(Roles = "SuperAdmin")] - Commented out to debug roles
public async Task<IActionResult> Index()
{
    var userID = User.FindFirstValue(ClaimTypes.NameIdentifier);
    var user = await _userManager.FindByIdAsync(userID);
    var roles = await _userManager.GetRolesAsync(user);

    return View();
}

当我调试用户时,我可以看到他们具有以下角色:

但他们仍然会在任何授权角色的控制器上收到 403。

这是我的程序.cs 的相关部分:

builder.Services.AddIdentity<TMSUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>()
    .AddRoleManager<RoleManager<IdentityRole>>()
    .AddTokenProvider<DataProtectorTokenProvider<TMSUser>>(TokenOptions.DefaultProvider);

builder.Services.ConfigureApplicationCookie(options =>
{
    options.AccessDeniedPath = new PathString("/Home/HandleError/401");
    options.LoginPath = new PathString("/Home/Portal");
});

builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddControllersWithViews();

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});

builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.AddTransient<ITools, Tools>();

builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);

builder.Services.AddMvc(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

var app = builder.Build();

app.UseStatusCodePagesWithReExecute("/Home/HandleError/{0}");
app.UseHsts();

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<TMSContext>();
    context.Database.EnsureCreated();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();

app.Run();

在过去的几个月里,我无数次地更改了我的代码,试图让它发挥作用,但现在我只是乞求帮助。这非常令人沮丧!我错过了什么?我的代码中的其他内容是否会阻止其正常工作?

谢谢!

c# asp.net asp.net-core asp.net-core-mvc asp.net-authorization
5个回答
0
投票

检查你得到了什么

User.FindAll(ClaimTypes.Role).ToList()

之后检查“超级管理员”是否出现在列表中?如果您的问题没有解决,请发布您的

GetRolesAsync
功能。


0
投票

看来你必须添加

services.AddDefaultIdentity<TMSUser>()

所以完整的代码看起来像这样

services.AddDefaultIdentity<ApplicationUser>()
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ICMSDbContext>()
                .AddClaimsPrincipalFactory<CustomClaimsPrincipalFactory>();

0
投票

解决方案比描述的要简单得多。如果您通过 .AddRoles() 添加角色并通过 .AddClaimsPrincipalFactory() 添加自定义声明;您必须继承 UserClaimsPrincipalFactory 而不是 UserClaimsPrincipalFactory,这是默认的。

所以你的代码应该如下所示:

public class CustomUserClaimsPrincipalFactory: UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
  {
    public CustomUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> options) : base(userManager, roleManager, options)
     {
     }
  //and below should be part with adding custom claim(s)
  }

0
投票

启用会话后就可以了。

builder.Services.AddSession();
app.UseSession();

-1
投票

我终于想出了一个解决方案。事情本来不应该这么复杂!我在其他版本.net中使用过角色,没有这个问题。

我创建了一个自定义授权过滤器,我只是访问数据库(我假设所有助手也这样做,所以没什么大不了的):

部分内容是我从此链接

获得的

首先,我用我的角色创建了一个模型:

public enum Role
{
    User, Admin, SuperAdmin
}

然后是自定义授权过滤器:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
    private readonly IList<Role> _roles;

    public AuthorizeAttribute(params Role[] roles)
    {
        _roles = roles ?? new Role[] { };
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        // Skip authorization if action is decorated with [AllowAnonymous] attribute
        var allowAnonymous = context.ActionDescriptor.EndpointMetadata
            .OfType<AllowAnonymousAttribute>().Any();

        if (allowAnonymous)
            return;

        // Authorization
        var user = context.HttpContext.User;

        if (user != null && _roles.Any())
        {
            using (var db = context.HttpContext.RequestServices
                .GetService<ApplicationDbContext>())
            {
                var userRoles = (from ur in db.UserRoles
                                 join r in db.Roles on ur.RoleId equals r.Id
                                 join u in db.Users on ur.UserId equals u.Id
                                 where u.UserName == user.Identity.Name
                                 select new
                                 {
                                     r.Name
                                 }).ToList();

                var isAuthorized = false;
                foreach (var role in userRoles)
                {
                    Role claimRole;
                    Enum.TryParse(role.Name, out claimRole);
                    if (_roles.Contains(claimRole))
                        isAuthorized = true;
                }

                if (isAuthorized)
                    return;
            }
        }

        context.Result = new UnauthorizedResult();
    }
}

我这样使用它:

[Authorize(Role.SuperAdmin)]
public async Task<IActionResult> Index()
{
    return View();
}

我确实喜欢这种方法。它将允许我在每个控制器/用户级别上做一些我想做的其他事情 - 我只是不敢相信它是如此复杂!

希望这对某人有帮助。如果这方面有任何明显的问题,请告诉我。我正式入伍了。

© www.soinside.com 2019 - 2024. All rights reserved.