Asp.net core 2.0+-多种身份验证方案(Cookie/承载) [英] Asp.net core 2.0+ - Multiple Authentication Schemes (Cookie / Bearer)

查看:132
本文介绍了Asp.net core 2.0+-多种身份验证方案(Cookie/承载)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been struggling to get multiple authentication schemes working correctly in Asp.net core 2.1.

我将Identity Server与隐式流一起使用,并使用OpenIdConnect作为协议.

I am using Identity Server with an implicit flow and OpenIdConnect as the protocol.

仅使用一种方案(例如Cookie或Bearer)授权操作或控制器时,该功能才能正常运行.

When authorizing an action or controller with one of the schemes only (e.g Cookie or Bearer) the functionality works correctly.

示例:

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

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

If I however I specify on the Authorize attribute both schemes, then it fails partially. Bearer works as normal, but when I try to view the page in the browser it attempts to redirect to a local Login page (http://localhost/Account/Login).

当我检查Identity Server的调试日志时,什么都没有返回,这很有意义,因为它没有尝试联系授权机构.但是,当我查看Test MVC站点的调试日志时,Bearer和Cookie方案都受到了挑战:

When I inspect the debug logs of Identity Server nothing is returned, which makes sense as it hasn't attempted to contact the Authority. However when I look at the debug log of the Test MVC Site both the Bearer and Cookie schemes are challenged:

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]

有人知道为什么这行不通吗?我给那个人喝啤酒!上个星期一直在找我.

Does anyone know why this isn't working? I'll the person a beer! It's been hunting me for the last week.

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

这是我的Startup.cs配置:

Here is my Startup.cs configuration:

   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;

推荐答案

我想对这个答案给出更好的解释:

I wanted to give a better explanation of this answer:

  1. 我必须在部分完成后移动 services.AddAuthorization 添加了两个方案.这样可以确保两个方案都已注册正确.
  1. I had to move services.AddAuthorization after the part were I added both of the schemes. This ensures both schemes are registered correctly.

 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. 然后,而不是将授权方案指定为Controller Action Authorize标签,使用时使用了全局策略 services.AddAuthorization

services.AddAuthorization(options =>
{
    var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
        CookieAuthenticationDefaults.AuthenticationScheme,
        JwtBearerDefaults.AuthenticationScheme);
    defaultAuthorizationPolicyBuilder =
        defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
    options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});

  1. 当我导航到API的任何部分时,它都不会重定向到登录"屏幕.我注意到,如果您首先通过导航到Identity Server登录,然后返回该页面,则实际上可以正常验证您的身份.因此,我提出了一点点hack的感觉.重要的是,这必须直接放在 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");
        }
      });

鲍勃是你的叔叔...并且感谢这篇文章的帮助!!oipapio.com/question-1510997

Bob's your uncle... and thanks to this post for helping considerably!! oipapio.com/question-1510997

这篇关于Asp.net core 2.0+-多种身份验证方案(Cookie/承载)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆