Uch*_*uku 5 c# asp.net authentication cookies bearer-token
我正在开发一个 ASP.net Core 2.0 应用程序,它使用 IdentityServer4 令牌服务器进行身份验证。我的应用程序有 Razor Pages,我想使用 Cookie 身份验证,它还有一个 API,我想使用 Bearer 令牌。
\n\n这是我的设置Startup.cs
:
public void ConfigureServices(IServiceCollection services) {\n//...\n services.AddAuthentication(options => { options.DefaultChallengeScheme = "oidc"; })\n .AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>\n {\n options.Authority = Configuration["OpenIDConnect:Authority"];\n options.ApiName = Configuration["OpenIDConnect:ApiName"];\n options.JwtBearerEvents.OnChallenge += async context =>\n {\n context.Response.StatusCode = StatusCodes.Status403Forbidden;\n context.HandleResponse();\n };\n })\n .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)\n .AddOpenIdConnect("oidc", options =>\n {\n options.SignInScheme = "Cookies";\n options.Authority = Configuration["OpenIdConnect:Authority"];\n options.RequireHttpsMetadata = false;\n options.ClientId = Configuration["OpenIdConnect:ClientId"];\n options.SaveTokens = true;\n options.Scope.Add("role");\n options.TokenValidationParameters = new TokenValidationParameters\n {\n NameClaimType = "name",\n RoleClaimType = "role"\n };\n });\n\n services.AddAuthorization(options =>\n {\n options.AddPolicy(Constants.Policies.ApiUserWithBearerToken,\n policy =>\n {\n policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);\n policy.AuthenticationSchemes.Remove(CookieAuthenticationDefaults.AuthenticationScheme);\n policy.AuthenticationSchemes.Remove("oidc");\n policy.RequireClaim("MobileClient", "true");\n policy.RequireClaim("ApiUser", "true");\n });\n });\n}\n\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env) {\n //\xe2\x80\xa6\n //\xe2\x80\xa6\n app.UseAuthentication();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n这是我尝试使用不记名令牌保护的 API 端点:
\n\n[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]\npublic class CatalogController : Controller\n{\n // \xe2\x80\xa6\n [HttpGet("current")]\n public async Task<IActionResult> Current()\n {\n // \xe2\x80\xa6\n } \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n我的问题是 ASP.net 似乎完全忽略了我的承载身份验证方案设置。如果我current
使用有效的不记名令牌请求端点,它会返回一个到 IdentityServer 的重定向,要求我登录。
这是来自 Kestrel 的消息日志:
\n\ninfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]\n Request starting HTTP/1.1 GET http://localhost:5001/api/Catalog/current\ninfo: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]\n Authorization failed for user: (null).\ninfo: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]\n Authorization failed for the request at filter \'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter\'.\ninfo: Microsoft.AspNetCore.Mvc.ChallengeResult[1]\n Executing ChallengeResult with authentication schemes ().\ninfo: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[12]\n AuthenticationScheme: oidc was challenged.\ninfo: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]\n Executed action Pinball.Web.Controllers.CatalogController.Current (Catalog.Web) in 1185.1356ms\ninfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]\n Request finished in 1871.9771ms 302\n
Run Code Online (Sandbox Code Playgroud)\n\n如果我删除默认的质询方案,那么 ASP.net 只会抛出一个异常,说明这是必需的。
\n\n我在这里缺少什么?
\n我遇到了同样的问题,既然我解决了它,我很高兴提供我的解决方案。当您通过调用services.AddIdentityServer()
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();
Run Code Online (Sandbox Code Playgroud)
之后您添加身份验证,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"];
});
Run Code Online (Sandbox Code Playgroud)
你也不需要.AddOpenIdConnect()
方法。
现在,请记住,完成此操作后,您将声明两种身份验证方法来服务您的身份验证请求。第一个是 cookie(由 IS 添加),另一个是通过调用添加的 JWT 承载.AddIdentityServerAuthentication()
。由于 cookie 是首先添加的,因此当任何请求需要进行身份验证时,它也会首先被调用,因此您需要指定在授权时要使用哪种方法,您可以使用以下方法正确执行此操作:
[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]
Run Code Online (Sandbox Code Playgroud)
我个人使用 IS default 但结果是一样的:
[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme), MobileAppController]
Run Code Online (Sandbox Code Playgroud)
有了这个,您应该拥有一个可以同时服务 API 请求和 Razor 页面的工作应用程序。