无法让 Identity Server 4 API 授权其自己的端点,而是发送登录页面
Posted
技术标签:
【中文标题】无法让 Identity Server 4 API 授权其自己的端点,而是发送登录页面【英文标题】:Can't get Identity Server 4 API to authorize its own endpoints, sends login page instead 【发布时间】:2021-08-28 11:35:08 【问题描述】:目前有效
我有两个 ASP.NET Core API:
-
一个业务 API,管理业务实体(想想产品、菜单等)
一个 IS4 API,管理用户和身份验证,并用于授权用户访问第一个
我是如何做到的:我在第二个 API 上的控制器是使用 Authorize(Roles = "Admin")
授权的,因此只有管理员可以访问它。示例:
[Authorize(Roles = "Admin")]
[ApiController]
[Route("[controller]")]
public class MenuController
...
基本上,我的前端使用 IS4 API 登录,它返回一个 JWT,而该 JWT 又用于向业务 API 验证自身。在我的 Startup.cs
业务 API 中,我有这个:
public void ConfigureServices(IServiceCollection services)
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
options.RequireHttpsMetadata = false;
options.Authority = "http://localhost:5000";
options.TokenValidationParameters = new TokenValidationParameters
ValidateAudience = false
;
);
services.AddApplication();
services.AddInfrastructure(Configuration);
services.AddControllers();
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseCors("AllowAll");
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
);
我的问题
以上工作正常。我试图在我的 IS4 API 的某些端点上做同样的事情,以便为管理员用户保留一些操作(删除用户、注册用户)。这是我为此目的在控制器中创建的一个基本端点:
[Authorize]
[HttpGet]
[Route("api/[controller]/debug")]
public async Task<IActionResult> DebugEndpoint()
return Ok("debug ok");
我也在Startup.cs
注册了API作为自己的权限,和第一个API一样:
public void ConfigureServices(IServiceCollection services)
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
services.AddHealthChecks();
services.AddIdentity<AppUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddOperationalStore(options =>
options.ConfigureDbContext = builder => builder.Usemysql(Configuration.GetConnectionString("Default"));
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30; // interval in seconds
)
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.TestUsers)
.AddAspNetIdentity<AppUser>();
services.AddLocalApiAuthentication();
services.AddAuthorization(options =>
options.AddPolicy("Admin", policy =>
var is4Policy = options.GetPolicy(IdentityServerConstants.LocalApi.PolicyName);
policy.Combine(is4Policy);
policy.RequireClaim(ClaimTypes.Role, "Admin");
);
);
services.AddTransient<IProfileService, IdentityClaimsProfileService>();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
options.RequireHttpsMetadata = false;
options.Authority = "http://localhost:5000";
options.TokenValidationParameters = new TokenValidationParameters
ValidateAudience = false
;
);
services.AddMvc(options =>
options.EnableEndpointRouting = false;
).SetCompatibilityVersion(CompatibilityVersion.Latest);
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
app.UseExceptionHandler(builder =>
builder.Run(async context =>
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
);
);
app.UseAuthorization();
app.UseCookiePolicy(new CookiePolicyOptions MinimumSameSitePolicy = SameSiteMode.None );
app.UseStaticFiles();
app.UseCors("AllowAll");
app.UseIdentityServer();
app.UseAuthentication();
app.UseMvc(routes =>
routes.MapRoute(
name: "default",
template: "controller=Home/action=Index/id?");
);
预期结果
如果我已登录,或者当我在注释中添加(Roles = "Admin")
时具有特定角色,我应该只能访问调试端点并获得“debug ok”。
实际结果
除非我删除 [Authorize]
注释,否则它总是让我再次调用登录页面。我在授权中传递了访问令牌,就像我对另一个 API 所做的那样,但是当它授权我使用另一个 API 时,它没有,就好像我什至没有传递访问令牌一样,我不明白为什么。
【问题讨论】:
你是从 VS 运行的吗? VS 不会自动以 ADMIN 开头。您需要右键单击 VS 快捷方式并选择以管理员身份运行。 这不是真正的 Windows 管理员状态,它只是 JWT 中传递的声明。 【参考方案1】:我必须将此添加到我的端点。
[Authorize(AuthenticationSchemes="Bearer")]
【讨论】:
以上是关于无法让 Identity Server 4 API 授权其自己的端点,而是发送登录页面的主要内容,如果未能解决你的问题,请参考以下文章
Identity Server 4 从入门到落地—— 创建Web Api
无法让分布式缓存与 Identity Server 一起使用
Identity Server 4 - Hybrid Flow - 保护API资源
Identity Server 4 的 API 授权不断返回 401 Unauthorized