【问题标题】:Asp.net core 2.0+ - Multiple Authentication Schemes (Cookie / Bearer)Asp.net core 2.0+ - 多种身份验证方案(Cookie / Bearer)
【发布时间】:2019-07-20 19:56:11
【问题描述】:

我一直在努力让多个身份验证方案在 Asp.net core 2.1 中正常工作。

我使用带有隐式流的 Identity Server 和 OpenIdConnect 作为协议。

当仅使用其中一种方案(例如 Cookie 或 Bearer)授权操作或控制器时,功能可以正常工作。

例子:

  [Authorize(AuthenticationSchemes = "Cookies")]
  [Route("Cookies")]
  public class BearerAndCookiesController : Controller {

但是,如果我在 Authorize 属性上指定了两个方案,那么它会部分失败。 Bearer 可以正常工作,但是当我尝试在浏览器中查看该页面时,它会尝试重定向到本地登录页面 (http://localhost/Account/Login)。

当我检查 Identity Server 的调试日志时,没有返回任何内容,这是有道理的,因为它没有尝试联系权威机构。但是,当我查看测试 MVC 站点的调试日志时,承载和 Cookie 方案都受到了挑战:

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5002/cookies  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Get", controller = "BearerAndCookies"}. Executing action MvcClient.Controllers.BearerAndCookiesController.Get (MvcClient)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (Bearer, Cookies).
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Cookies was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action MvcClient.Controllers.BearerAndCookiesController.Get (MvcClient) in 68.1922ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 93.2016ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5002/Account/Login?ReturnUrl=%2Fcookies  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 30.2532ms 404 
Failed to load resource: the server responded with a status of 404 (Not Found) [http://localhost:5002/Account/Login?ReturnUrl=%2Fcookies]

有谁知道为什么这不起作用?我会为人喝啤酒!上周它一直在追捕我。

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-2.2&tabs=aspnetcore2x

这是我的 Startup.cs 配置:

   public void ConfigureServices(IServiceCollection services) {

      services.AddMvc();

      JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

      services.AddAuthentication(options => {
        options.DefaultScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";
      })
      .AddJwtBearer(options => {
        options.Authority = "http://localhost:5000";
        options.Audience = "myApi";
        options.RequireHttpsMetadata = false;
      })
      .AddCookie("Cookies")
      .AddOpenIdConnect("oidc", options => {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;

        options.ClientId = "myApi";
        options.SaveTokens = true;
      });
    }
  [Authorize(AuthenticationSchemes = AuthSchemes)]
  [Route("Cookies")]
  public class BearerAndCookiesController : Controller {

    private const string AuthSchemes =
      JwtBearerDefaults.AuthenticationScheme + "," +
      CookieAuthenticationDefaults.AuthenticationScheme;

【问题讨论】:

    标签: asp.net-core cookies authorization identityserver4 bearer-token


    【解决方案1】:

    我想更好地解释这个答案:

    1. 我必须在部件之后移动 services.AddAuthorization 添加了这两个方案。这确保了两个方案都已注册 正确。
     JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    
          services.AddAuthentication(options => {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
          })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options => {
              options.SignInScheme = "Cookies";
              options.Authority = "http://localhost:5000";
              options.RequireHttpsMetadata = false;
              options.ClientId = "myApi";
              options.SaveTokens = true;
            }).AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options => {
              options.Authority = "http://localhost:5000";
              options.ApiName = "myApi";
              options.RequireHttpsMetadata = false;
            });
    
          services.AddAuthorization(options => {
          ...
          });
    
    1. 然后将授权方案指定为 控制器动作授权标签,我使用时使用了全局策略 services.AddAuthorization
    services.AddAuthorization(options =>
    {
        var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
            CookieAuthenticationDefaults.AuthenticationScheme,
            JwtBearerDefaults.AuthenticationScheme);
        defaultAuthorizationPolicyBuilder =
            defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
        options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
    });
    
    1. 当我导航到 API 的任何部分时,它不会重定向到登录屏幕。我注意到,如果您首先通过导航到 Identity Server 登录,然后返回该页面,它实际上会像往常一样对您进行身份验证。所以我加入了一点点黑客的感觉。重要的是,这直接进入 app.UseAuthentication 下。
      app.UseAuthentication();
          app.Use(async (context, next) => {
            await next();
            var bearerAuth = context.Request.Headers["Authorization"]
                               .FirstOrDefault()?.StartsWith("Bearer ") ?? false;
            if (context.Response.StatusCode == 401
                && !context.User.Identity.IsAuthenticated
                && !bearerAuth) {
              await context.ChallengeAsync("oidc");
            }
          });
    

    Bob 是你的叔叔……感谢这篇文章的大力帮助!! oipapio.com/question-1510997

    【讨论】:

    • 当我将它与带有任何参数的[Authorize] 结合使用时,这不起作用,例如[Authorize(Roles=...)] 因为DefaultPolicy 不适用于这种情况。
    猜你喜欢
    • 2021-10-18
    • 2019-08-31
    • 2018-03-23
    • 2022-01-04
    • 2018-03-30
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2019-04-19
    相关资源
    最近更新 更多