ASP.NET Core JWT / Windows Аутентификация HTTP 400 Ошибка - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть веб-API ASP.NET Core 2.1, который в настоящее время требует, чтобы пользователи вводили имя пользователя / пароль для получения JWT для авторизации.Я хочу добавить опцию использования аутентификации Windows для получения JWT.В конечном итоге я планирую иметь два контроллера авторизации, один для имени пользователя / пароля, другой для проверки подлинности Windows.

Чтобы проверить это, я сначала включил проверку подлинности Windows в IIS express, щелкнув правой кнопкой мыши по своему проекту и выбравСвойства.

Hey look, windows auth!

Затем я создал простой тестовый контроллер, чтобы проверить, могу ли я проходить аутентификацию с помощью своих учетных данных Windows.

[Authorize(AuthenticationSchemes = "Windows")]
[Route("api/ping")]
public class PingController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Pong" };
    }
}

Этоказалось, что работает, как когда я перешел к этой конечной точке в моем браузере, экран отображал Pong, как и ожидалось.

Однако я сталкиваюсь с проблемами, когда я пытаюсь получить доступ к любому из моих других контроллеров, которые используют аутентификацию BearerСхемы.Контроллеры объявляют свою схему аутентификации следующим образом:

[Authorize(Policy = "MyPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Всякий раз, когда я делаю запрос к одному из этих контроллеров, я получаю следующую ошибку:

HTTP Error 400. The request is badly formed.

Этот же запрос прекрасно работает сПроверка подлинности Windows отключена.

Как обеспечить проверку подлинности Windows на некоторых контроллерах и проверку подлинности на носителе на других?

1 Ответ

0 голосов
/ 16 ноября 2018

Как обеспечить проверку подлинности Windows на некоторых контроллерах и проверку подлинности на носителе на других?

Во-первых, я должен сказать, что это как-то странно при работе со смешанными схемами JWT и Windows Authentication. Я имею в виду, когда пользователь, который не аутентифицирован JwtBearer, пытается получить доступ к ресурсам URL, защищенным схемой JwtBearer, будет подвергнут сомнению аутентификацией Windows.

Во-вторых, что касается вашего вопроса, мы можем настроить аутентификацию JwtBearer на использование пользовательского токена, который не используется в качестве заголовка HTTP (т.е. Authorization: Bearer xxxx_yyyy_zzz) . Например, отправьте токен JWT по строке запроса или пользовательскому заголовку.

Как в деталях:

Настройка JwtBearer аутентификации для чтения токена из строки запроса:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options=> {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
            options.Events = new JwtBearerEvents() {
                OnMessageReceived = async (context) =>{
                    var bearer=context.HttpContext.Request.Query["bearer"].FirstOrDefault();
                    if(!String.IsNullOrEmpty(bearer)){
                        context.Token = bearer;
                    }
                },
            };
        });

Для целей тестирования я добавляю фиктивный обработчик политики для вашего MyPolicy:

services.AddAuthorization(o => {
    o.AddPolicy("MyPolicy",p => {
        p.Requirements.Add(new MyPolicyRequirement());
    });
});
services.AddSingleton<IAuthorizationHandler,MyPolicyRequirementHandler>();
services.AddHttpContextAccessor();

Здесь MyPolicyRequirementHandler:

public class MyPolicyRequirementHandler : AuthorizationHandler<MyPolicyRequirement>
{

    public MyPolicyRequirementHandler()
    {
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyPolicyRequirement requirement)
    {
        var user= context.User;
        if (user.Identity.IsAuthenticated)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

И два контроллера защищены Аутентификацией Windows или JwtBearer:

[Authorize(AuthenticationSchemes = "Windows")]
[Route("api/[controller]")]
[ApiController]
public class PingController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Pong" };
    }
}

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy ="MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class FooController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "Bar" };
    }
}

Контрольный пример:

Тест с аутентификацией Windows

Снимок экрана при доступе к /api/ping

enter image description here

Тест с аутентификацией на носителе Jwt

Во-первых, сгенерируйте JwtToken на стороне сервера:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s

А затем отправьте HTTP-запрос GET в конечную точку /api/foo со строкой запроса bearer=xxx_yyy_zzz:

GET https://localhost:44385/api/foo?bearer=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s HTTP/1.1

вернет [foo] как и ожидалось:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTZcV2luZG93c0F1dGh0ZW50aWNhdGlvbkFuZEp3dEF1dGhlbnRpY2F0aW9uXEFwcFxhcGlcZm9v?=
X-Powered-By: ASP.NET

["Bar"]
...