Asp.net core 2.0+ - несколько схем аутентификации (cookie / носитель)

Я изо всех сил пытался заставить несколько схем аутентификации работать правильно в ядре Asp.net 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;

person Slavvy    schedule 20.07.2019    source источник


Ответы (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");
        }
      });

Боб - твой дядя ... и спасибо этому посту за большую помощь !! oipapio.com/question-1510997

person Slavvy    schedule 21.07.2019
comment
Это не работает, когда я использую его в сочетании с [Authorize] с любыми параметрами, например. [Authorize(Roles=...)], потому что DefaultPolicy в таком случае не применяется. - person Vlad; 15.04.2021