角色授权不适用于React / ASP.NET Core API

时间:2020-05-12 05:50:49

标签: c# reactjs asp.net-core identityserver4

我使用个人用户帐户在asp.net核心中使用默认的react模板创建了一个react项目。 [Authorize]属性工作正常,但是当我尝试实现[Authorize(Roles =“ Administrator”)]时,我得到了403状态代码。

我添加了ProfileService来添加声明。

ProfileService.cs

public class ProfileService : IProfileService
{
    protected UserManager<ApplicationUser> mUserManager;

    public ProfileService(UserManager<ApplicationUser> userManager)
    {
        mUserManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        ApplicationUser user = await mUserManager.GetUserAsync(context.Subject);

        IList<string> roles = await mUserManager.GetRolesAsync(user);

        IList<Claim> roleClaims = new List<Claim>();
        foreach (string role in roles)
        {
            roleClaims.Add(new Claim(JwtClaimTypes.Role, role));
        }
        context.IssuedClaims.AddRange(roleClaims);
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        return Task.CompletedTask;
    }
}

“角色”:我的JWT令牌中存在“管理员”。

我已将Authorize属性添加到控制器中。

    [Authorize(Roles = "Administrator")]
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Order>>> GetOrders()
    {
        return await _context.Orders.ToListAsync();
    }

我还如下配置了Startup.cs。

Startup.cs

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));

        //services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        //    .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddRoles<IdentityRole>()
            .AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

        services.AddAuthentication()
            .AddIdentityServerJwt();

        services.AddAuthorization();

        services.Configure<IdentityOptions>(options =>
        {
            options.ClaimsIdentity.RoleClaimType = JwtClaimTypes.Role;
        });

        services.AddTransient<IProfileService, ProfileService>();

        services.AddControllersWithViews();
        services.AddRazorPages();

        // In production, the React files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/build";
        });
    }

不确定我要怎么做。

2 个答案:

答案 0 :(得分:0)

如果要使用内置的角色授权,则必须更改为此分配角色声明的方式:

 roleClaims.Add(new Claim(JwtClaimTypes.Role, role));

对此:

 roleClaims.Add(new Claim(ClaimTypes.Role, role));

答案 1 :(得分:0)

更好的方法是使用基于策略的授权 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-5.0

  1. ConfigureServices 中配置您的政策:

         services.AddAuthorization(options =>
         {
             options.AddPolicy("RequireAdministratorRole",
                 policy => policy.RequireClaim(ClaimTypes.Role, "Administrator"));
         });
    
  2. 在 ProfileService 中

             var claims = roles.Select(role => new Claim(ClaimTypes.Role, role)).ToList();
    
  3. 添加到控制器:

    [授权(Policy = "RequireAdministratorRole")]

它可能不起作用,因为 Microsoft 声明名称不一致可以通过以下方式修复:

            services.Configure<JwtBearerOptions>(options =>
        {
            var validator = options.SecurityTokenValidators.OfType<JwtSecurityTokenHandler>().SingleOrDefault();

            // Turn off Microsoft's JWT handler that maps claim types to .NET's long claim type names
            validator.InboundClaimTypeMap = new Dictionary<string, string>();
            validator.OutboundClaimTypeMap = new Dictionary<string, string>();
        });