c# - 如何在我的 ASP.net Core 应用程序中同时使用 Bearer 和 Cookie 身份验证?

标签 c# asp.net authentication cookies bearer-token

我正在开发一个使用 IdentityServer4 token 服务器进行身份验证的 ASP.net Core 2.0 应用程序。我的应用程序有 Razor Pages,我想使用 Cookie 身份验证,它还有一个 API,我想使用 Bearer token 。

这是我在 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();
}

这是我尝试使用 Bearer token 保护的 API 端点:

[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]
public class CatalogController : Controller
{
    // …
    [HttpGet("current")]
    public async Task<IActionResult> Current()
    {
        // …
    }        
}

我的问题是 ASP.net 似乎完全忽略了我的 Bearer 身份验证方案设置。如果我使用有效的承载 token 请求 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 只会抛出一个异常,说明它是必需的。

我在这里错过了什么?

最佳答案

我遇到了同样的问题,既然我解决了它,我很高兴提供我的解决方案。 当您通过调用 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 bearer。 由于 cookie 是首先添加的,因此当任何请求需要进行身份验证时,它也会首先被调用,因此您需要指定您希望在授权点使用哪种方法,您通过使用正确地做到了这一点:

[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = "Bearer"), MobileAppController]

我个人使用IS默认,但结果是一样的:

[Route("api/[controller]"), Authorize(Policy = "ApiUserWithBearerToken", AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme), MobileAppController]

有了这个,您应该有一个可以同时处理 API 请求和 Razor 页面的工作应用。

关于c# - 如何在我的 ASP.net Core 应用程序中同时使用 Bearer 和 Cookie 身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49333236/

相关文章:

c# 按数字拆分字符串值

c# - 将引用属性映射到抽象父级

c# - 如何将文件路径从我的代码中取出并放入 mysql 的插入语句中?

android - 如何解决“"caller uid XXXX is different than the authenticator' s uid”问题?

c# - 如何从 c++/cli 静态函数返回托管类

c# - 使用 epplus 设置单元格宽度会影响整列

asp.net - 如何将成员资格表与 Entity Framework 集成? ASP.net

java - 具有 HTTP 基本身份验证或匿名访问相同 URI 的 Shiro

node.js - 使用 express-session 和 connect-session-sequelize 时 this.sessionModel.find 不是函数

c# - 将 C# 连接到 MySQL 上的远程数据库