我正在使用一个使用IdentityServer4令牌服务器进行身份验证的ASP.net Core 2.0应用程序。我的应用程序有Razor Pages,我希望使用Cookie认证,它还有一个API,我想使用Bearer令牌。
这是我Startup.cs
中的设置:
public void ConfigureServices(IServiceCollection services) {
//...
services.AddAuthentication(options => { options.DefaultChallengeScheme = "oidc"; })
.AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = Configuration["OpenIDConnect:Authority"];
options.ApiName = Configuration["OpenIDConnect:ApiName"];
options.JwtBearerEvents.OnChallenge += async context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
context.HandleResponse();
};
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = Configuration["OpenIdConnect:Authority"];
options.RequireHttpsMetadata = false;
options.ClientId = Configuration["OpenIdConnect:ClientId"];
options.SaveTokens = true;
options.Scope.Add("role");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
services.AddAuthorization(options =>
{
options.AddPolicy(Constants.Policies.ApiUserWithBearerToken,
policy =>
{
policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
policy.AuthenticationSchemes.Remove(CookieAuthenticationDefaults.AuthenticationScheme);
policy.AuthenticationSchemes.Remove("oidc");
policy.RequireClaim("MobileClient", "true");
policy.RequireClaim("ApiUser", "true");
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
//…
//…
app.UseAuthentication();
}
这是我尝试使用承载令牌保护的API端点:
[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]
public class CatalogController : Controller
{
// …
[HttpGet("current")]
public async Task<IActionResult> Current()
{
// …
}
}
我的问题是ASP.net似乎完全忽略了我的Bearer身份验证方案设置。如果我使用有效的承载令牌请求current
端点,它会返回一个重定向到IdentityServer,要求我登录。
这是来自Kestrel的消息日志:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5001/api/Catalog/current
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[12]
AuthenticationScheme: oidc was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action Pinball.Web.Controllers.CatalogController.Current (Catalog.Web) in 1185.1356ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 1871.9771ms 302
如果我删除了默认的质询方案,那么ASP.net会抛出一个例外情况,说明它是必需的。
我在这里缺少什么?
答案 0 :(得分:0)
我遇到了同样的问题,自从我解决了问题,我很高兴提供自己的解决方案。
当您通过调用services.AddIdentityServer()
添加Identity Server时,默认情况下会添加cookie身份验证,如您在此处看到的https://github.com/IdentityServer/IdentityServer4/blob/75b1a660c3cab2580112e6e0288f3f6bed8189f9/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs
builder
.AddRequiredPlatformServices()
.AddCookieAuthentication() // <-- Cookie auth added
.AddCoreServices()
.AddDefaultEndpoints()
.AddPluggableServices()
.AddValidators()
.AddResponseGenerators()
.AddDefaultSecretParsers()
.AddDefaultSecretValidators();
之后,您添加带有services.AddAuthentication()
的身份验证,因此此时您无需再添加cookie身份验证,因为它已经被添加了。
您只需添加以下代码即可添加IS身份验证:
services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration["Settings:Authentication:Authority"];
options.RequireHttpsMetadata = !CurrentEnvironment.IsDevelopment();
options.ApiName = Configuration["Settings:Authentication:ApiName"];
options.ApiSecret = Configuration["Settings:Authentication:ApiSecret"];
});
您也不需要.AddOpenIdConnect()
方法。
现在,请记住,完成此操作后,您已经声明了两种用于服务身份验证请求的身份验证方法。第一个是cookie(由IS添加),另一个是通过调用.AddIdentityServerAuthentication()
添加的JWT承载。
由于cookie是首先添加的,因此在需要验证任何请求时也将首先调用它,因此,您需要指定要在授权时使用哪种方法,可以使用:
[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]
我个人使用IS默认值,但结果是相同的:
[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme), MobileAppController]
有了这个,您应该有一个可以同时处理API请求和Razor页面的应用程序。