为什么我不能在我的 API 控制器中使用角色授权
Why can't I use role authorization in my API controller
我用 asp.net 核心中的反应模板创建了一个反应项目,带有个人用户帐户。我看了一圈,发现我需要在启动文件中添加角色并添加配置文件服务,这似乎已经成功了一半。
我可以在我的授权令牌中看到这样的角色:
"role": [
"admin",
"bookkeeping" ],
但是当我将 [Authorize(Roles = "admin")]
标签添加到我的控制器时,请求现在被禁止了,即使我可以看到我的令牌包含角色 "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 控制器与我的身份服务器在同一个项目中。
提前感谢您的帮助。
像这样更改启动时角色的默认声明类型:
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.RoleClaimType = JwtClaimTypes.Role;
});
我用 asp.net 核心中的反应模板创建了一个反应项目,带有个人用户帐户。我看了一圈,发现我需要在启动文件中添加角色并添加配置文件服务,这似乎已经成功了一半。
我可以在我的授权令牌中看到这样的角色:
"role": [
"admin",
"bookkeeping" ],
但是当我将 [Authorize(Roles = "admin")]
标签添加到我的控制器时,请求现在被禁止了,即使我可以看到我的令牌包含角色 "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 控制器与我的身份服务器在同一个项目中。
提前感谢您的帮助。
像这样更改启动时角色的默认声明类型:
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.RoleClaimType = JwtClaimTypes.Role;
});