Использование JWT с секретным ключом для обработки единого входа

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

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

Я ищу простой пример того, как это может выглядеть с точки зрения кода, как на стороне отправителя, так и на стороне получателя. Концом получателя будет конечная точка WebAPI, которая будет обрабатывать вход в систему, а затем перенаправлять на главную страницу веб-сайта только для членов, если вход в систему выполнен успешно.

Он разработан на C#.

«Я ищу простой пример того, как это может выглядеть с точки зрения кода» — такой вещи не существует: просто слишком много движущихся частей. Кроме того, пожалуйста, уточните, что именно вы подразумеваете под «единым входом», потому что тот факт, что вы используете JWT, не означает, например, что вы используете свой собственный IdP OIDC.

Dai 20.11.2022 03:45

Ваши сети csr или ssr с C#? Сколько веб-сайтов и микросервисов в вашей инфраструктуре? Вы ищете стратегию предприятия или просто poc?

JRichardsz 20.11.2022 03:50

@JRichardsz это SSR с C# на приемном конце. Просто простой POC, чтобы помочь с моим собственным пониманием лучшего решения и способа справиться с задачей. У меня есть сам логин, поэтому у меня есть код, который может принимать только имя пользователя, а затем регистрировать пользователя. Шаг, который мне не хватает, — это шифрование и дешифрование данных JWT с использованием секретного ключа.

brother 20.11.2022 08:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
120
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Элементарные советы

  • Обычно и часто пользователь/пароль заменяются на новый JWT.

  • JWT не должен хранить ничего разумного, например, пароль. Но некоторые компании вроде Microsoft хранят не осмысленные значения, а много информации https://gist.github.com/jrichardsz/6512f9b2b4c38620bf00e24c71b6cf2d

  • Для предприятий процесс шифрования и дешифрования не должен выполняться на уровне микросервиса. Это должно выполняться другим сервером, например: Auth0, okta, Keycloack и т. д.

  • Ваш микросервис только получает токен и отправляет его на платформу безопасности. Лучший способ сделать это — использовать промежуточное ПО на любом языке. Это для c#

  • Платформа безопасности возвращает ответ с данными в синтаксисе, который клиент (С# в вашем случае) понимает, является ли токен законным, действительным, не просроченным, существует пользователь, пользователю разрешено выполнять операцию и т. д. Я использовал это в некоторой реализации в на что я сказал: «Пользователю разрешено выполнять эту операцию, и это его имя пользователя»

    конечная точка: acme-security.com/v1/oauth2/token/validate

    просьба: eyJ0eXAiOiJKV1Qi...

    отклик:

    {
    "isAllowed": true,
    "subject": "[email protected]"
    }
    
  • Также вы можете сделать это с помощью API-шлюза.

  • В более реальном сценарии нам нужно больше, чем простая проверка jwt. Нам нужно убедиться, что пользователю admin/guest разрешено выполнять определенные конечные точки. Мы не хотим, чтобы сотрудник напрямую вызывал конечную точку платежа, устанавливающую свою зарплату :/

  • Следуйте спецификации oauth2, если вы будете внедрять собственную платформу безопасности.

  • Jwt должен быть отправлен как заголовок авторизации

  • ВАЖНО: если вы будете реализовывать собственную генерацию и проверку jwt, используйте переменные ENV, чтобы скрыть секрет и максимально защитить его для вашей производственной среды.

Обработка JWT с С# netcore 5

Если предыдущие шаги понятны, вам нужен только один из этих подходов:

  • Используйте некоторые платформы IAM или безопасности, такие как auth0, okta, keycloack и т. д.
  • Простой С# web/microservice/api (который также функционирует как платформа безопасности) для получения токена и возврата, если пользователю разрешено
  • Класс для проверки внутри целевого микросервиса

Генерация JWT

public string GenerateToken(User user)
{
    // generate token that is valid for 7 days
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

JWT-декодирование или проверка

public int? ValidateToken(string token)
{
    if (token == null) 
        return null;

    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
    try
    {
        tokenHandler.ValidateToken(token, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false,
            // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
            ClockSkew = TimeSpan.Zero
        }, out SecurityToken validatedToken);

        var jwtToken = (JwtSecurityToken)validatedToken;
        var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);

        // return user id from JWT token if validation successful
        return userId;
    }
    catch
    {
        // return null if validation fails
        return null;
    }
}

Источник: https://jasonwatmore.com/post/2021/06/02/net-5-create-and-validate-jwt-tokens-use-custom-jwt-middleware

Этот код выдает ошибки, когда срок действия токена истек или какой-то приятель пытается отправить jwt без вашего SUPER_SECRET_KEY.

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

[HttpGet]
public ActionResult<List<Dictionary<string, object>>> findAllEmployees()
{
    //get jwt from http received headers
    validationResponse = ValidateToken(jwt)
    //if you have a security platform, callhere instead
    //ValidateToken(jwt)
    //if validationResponse.isAllowed ....
    var list = this.employeeService.findAllEmployees();
    return Ok(list);
}

или с промежуточным программным обеспечением, таким как профессионал, чтобы содержать в чистоте ваши окончательные контроллеры

Лекции

Другие вопросы по теме