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

tvmytwxo  于 2023-02-06  发布在  .NET
关注(0)|答案(3)|浏览(283)

我已经通读了无数的教程、文章和问题。
我不明白为什么[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();

在过去的几个月里,我已经无数次地修改了代码,试图让它正常工作,但是现在我只是在乞求帮助。这非常令人沮丧!我错过了什么?我的代码中是否有其他东西阻止了它正常工作?
谢谢大家!

p8h8hvxi

p8h8hvxi1#

User.FindAll(ClaimTypes.Role).ToList()检查你得到了什么
之后,检查“超级管理员”来列表或没有?,如果你的问题没有解决比后你的GetRolesAsync功能。

enyaitl3

enyaitl32#

看起来你必须添加services.AddDefaultIdentity<TMSUser>()
所以完整的代码应该是

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

0kjbasz63#

我终于想出了一个解决这个问题的办法。它不应该这么复杂!我在其他版本的.net中使用角色没有这个问题。
我创建了一个自定义的Authorize Filter,我只是点击了数据库(我假设所有的助手都这样做,所以这不是什么大问题):
我从这个链接中得到的部分信息
首先,我用我的角色创建了一个模型:

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();
}

我确实喜欢这种方法,它允许我在每个控制器/用户级别上做一些我想做的事情--我只是不敢相信它会这么复杂!
希望这对大家有所帮助。如果有任何明显的问题,请让我知道。我正式球。

相关问题