ASP.Net Core MVC / API / SignalR - изменение схем аутентификации (Cookie & JWT) - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть веб-приложение .Net Core 2.2 MVC, в которое я добавил контроллеры API и концентраторы SignalR.С другой стороны, у меня есть мобильное приложение, которое вызывает методы-концентраторы.Прежде чем вызывать концентраторы из приложения, я проверяю подлинность своих пользователей через вызов API - возвращаю токен JWT - и использую этот токен для будущих запросов, так что я могу использовать Context.User.Identity.Name в своих методах концентратора:

public static async Task<string> GetValidToken(string userName, string password)
{
   using (var client = new HttpClient())
   {
     client.BaseAddress = new Uri(_API_BASE_URI);
     client.DefaultRequestHeaders.Accept.Clear();
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

     LoginViewModel loginVM = new LoginViewModel() { Email = userName, Password = password, RememberMe = false };
     var formContent = Newtonsoft.Json.JsonConvert.SerializeObject(loginVM);
     var content = new StringContent(formContent, Encoding.UTF8, "application/json");
     HttpResponseMessage responseMessage;
     try
     {
        responseMessage = await client.PostAsync("/api/user/authenticate", content);
        var responseJson = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); ;
        var jObject = JObject.Parse(responseJson);
        _TOKEN = jObject.GetValue("token").ToString();
        return _TOKEN;
     }catch
        [...]

Затем с помощью токена:

_connection = new HubConnectionBuilder().WithUrl(ApiCommunication._API_BASE_URI + "/network", options =>
{
  options.AccessTokenProvider = () => Task.FromResult(token);
}).Build();

Пока все хорошо.Он работает, как и ожидалось, на моем мобильном приложении.Но для того, чтобы это работало, мне пришлось установить этот фрагмент кода на стороне сервера (Startup.cs):

services.AddAuthentication(options =>
{
   options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
   options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
 })
 .AddJwtBearer(x =>
 {
    x.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            ...

Это больше не позволяет мне использовать аутентификацию с помощью cookie и, следовательно, веб-приложение mvcбольше не работает должным образом, так как не может получить текущего аутентифицированного пользователя среди запросов.

Удаление строк:

options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

делает веб-приложение работающим корректно, но немобильное приложение (сбои вызовов хабов из-за Context.User.Identity.Name равно нулю).

Я искал все вокруг, как обрабатывать различные схемы (в моем случае cookie + jwt) и, насколько я понимаю, этоЭто больше не возможно по дизайну.

Есть ли возможный обходной путь для использования двойной схемы или я что-то упустил?

Я подумал, что, возможно, вместо этого я буду использовать 2 отдельных проекта и использую один с аутентификацией Cookie.а другой с JWT?

Заранее спасибо.

1 Ответ

0 голосов
/ 28 декабря 2018

Существует несколько способов решения проблемы, с которой вы столкнулись, но сначала давайте разберемся, почему она в настоящее время не работает.

Что DefaultAuthenticateScheme означает

Когда вы устанавливаете значение в DefaultAuthenticateScheme свойство AuthenticationOptions, вы указываете промежуточному программному обеспечению аутентификации пытаться аутентифицировать каждый HTTP-запрос по этой конкретной схеме.Я предполагаю, что вы используете ASP.NET Identity для проверки подлинности на основе файлов cookie, и при вызове AddIdentity она регистрирует схему проверки подлинности с использованием файлов cookie по умолчанию для целей проверки подлинности;Вы можете увидеть это в исходном коде на GitHub .

Однако это не означает, что вы не можете использовать любую другую схему аутентификации в своем приложении.

политика по умолчанию для системы авторизации

Если все защищенные конечные точки вашего приложения должны быть доступны для клиентов, прошедших проверку подлинности с помощью файлов cookie или JWT, одним из вариантов является использование политики по умолчанию для системы авторизации.Эта специальная политика используется, когда вы используете «пустые» экземпляры класса AuthorizeAttribute - либо в качестве атрибута для украшения контроллеров / действий, либо глобально на уровне приложения с помощью new AuthorizeFilter(new AuthorizeAttribute()).

Политики по умолчанию.устанавливается только для аутентифицированного пользователя, но не определяет, какие схемы аутентификации нужно «попробовать» для аутентификации запроса.В результате он полагается на процесс аутентификации, который уже был выполнен.Это объясняет поведение, которое вы испытываете, когда одновременно работает только одна из 2 схем.

Мы можем изменить политику по умолчанию с помощью небольшого кода:

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-cookie-authentication-scheme", "your-jwt-authentication-scheme")
        .Build();
})

Специальные политики авторизации

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

Они работают точно так же, какполитика по умолчанию, ожидайте, что вы можете выбрать для конечной точки, какой из них применяется.Вы можете добавить политики следующим образом:

services.AddAuthorization(options =>
{
    options.AddPolicy("Cookies", new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-cookie-authentication-scheme")
        .Build());

    options.AddPolicy("JWT", new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-jwt-authentication-scheme")
        .Build());
})

Затем вы можете ссылаться на эти политики в соответствующих конечных точках, отмечая их [Authorize(Policy = "<policy-name>")].В качестве примечания: если единственным отличием между вашими политиками является схема аутентификации, можно достичь того же результата без создания политик и обращения к соответствующей схеме (ам) аутентификации в атрибутах [Authorize] со свойством AuthenticationSchemes.

Политики полезны, когда у вас есть более сложные правила, например, , для которых конкретное утверждение требует, например, это конкретное значение .

Надеюсь, это поможет, дайте мне знать, как выидти!?

...