Asp.net core 2.0+-多种身份验证方案(Cookie /承载)

时间:2019-07-20 19:56:11

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

我一直在努力使多种身份验证方案在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的调试日志时,什么也没有返回,这是有道理的,因为它没有尝试联系授权机构。但是,当我查看Test MVC站点的调试日志时,Bearer和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;

1 个答案:

答案 0 :(得分: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. 然后,而不是将授权方案指定为     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