【问题标题】:Why can't I use role authorization in my API controller为什么我不能在我的 API 控制器中使用角色授权
【发布时间】:2020-06-10 08:18:59
【问题描述】:

我使用 asp.net 核心中的反应模板创建了一个反应项目,其中包含个人用户帐户。我环顾四周,发现我需要在启动文件中添加角色并添加配置文件服务,这似乎成功了一半。

我可以像这样在我的授权令牌中看到角色:

"role": [
    "admin",
    "bookkeeping" ], 

但是当我将[Authorize(Roles = "admin")] 标签添加到我的控制器时,请求现在被禁止,即使我可以看到我的令牌包含角色“管理员”。

我在这里遗漏了什么或做错了什么?

这是配置文件服务:

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.Add(new Claim(JwtClaimTypes.Name, user.UserName));
        context.IssuedClaims.AddRange(roleClaims);
    }

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

这是我的启动文件:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        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(options =>
        {
            options.AddPolicy("RequireAdministratorRole",
                 policy => policy.RequireRole("admin"));
        });

        services.AddTransient<IProfileService, ProfileService>();
        services.AddControllersWithViews()
            .AddNewtonsoftJson(options =>
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );
        services.AddRazorPages();

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

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSpaStaticFiles();
        app.UseRouting();
        app.UseAuthentication();
        app.UseIdentityServer();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";
            if (env.IsDevelopment())
            {
                spa.UseReactDevelopmentServer(npmScript: "start");
            }
        });
    }
}

我的 API 控制器的小版本:

[Authorize(Roles = "admin")]
[Route("api/[controller]")]
public class SampleDataController : ControllerBase
{
    private readonly ApplicationDbContext _db;

    public SampleDataController(ApplicationDbContext db)
    {
        _db = db;
    }   
    [HttpGet("[action]")]
    public IEnumerable<Order> GetOrderList()
    {

        return _db.Order.ToList();
    }

}

还有我的获取方法

async populateOrderList() {
    const token = await authService.getAccessToken();
    const response = await fetch('api/SampleData/GetOrderList', {
        headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
    });
    const data = await response.json();
    this.setState({ orderList: data });
}

正如您在我的启动文件中看到的那样,我也尝试使用一个策略,改为使用标签[Authorize(Policy = "RequireAdministratorRole")]。当我只使用[Authorize]时它也可以正常工作

编辑:我的 api 控制器与我的身份服务器在同一个项目中。

提前感谢您的帮助。

【问题讨论】:

  • 删除 Authorize 属性后会发生什么?如果它仍然显示为未经授权,那么还有另一个原因,例如有cors的东西。
  • 嗨@RuardvanElburg,是的,没有授权就可以正常工作。
  • 我想知道,你有这个我们可以看到的地方的工作结果吗?我遇到了类似的问题。谢谢

标签: reactjs asp.net-core identityserver4 asp.net-core-identity


【解决方案1】:

像这样更改启动中角色的默认声明类型:

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

【讨论】:

  • 嗨@Mehrdad,感谢您的帮助。遗憾的是,它仍然被禁止。
  • 请在您的控制器上同时尝试 [Authorize(LocalApi.PolicyName)] 和 [Authorize(Roles = "admin")]
  • 嗨@Mehrdad,再次感谢。我现在收到内部服务器错误。响应:System.InvalidOperationException:未找到名为“IdentityServerAccessToken”的 AuthorizationPolicy。
  • 我在 identityserver4 上工作了 2 年,现在用我的控制器上的角色测试授权,没有任何问题,我认为遗漏了一些东西。你能和我分享你在某个地方的项目吗?
  • 我更改了启动文件中的顺序,现在它可以工作了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 2014-01-31
相关资源
最近更新 更多