Авторизуйтесь через JWT Token

ASP.NET Core 5 с ASP.NET Identity 3.0, я использую как веб-страницы, так и API-интерфейсы. Я использую OpenIddict для выдачи токена JWT и аутентификации. Мой код выглядит так:

    X509Certificate2 c = new X509Certificate2(@"tokensign.p12", "MyCertificatePassword");

    services.AddOpenIddict<WebUser, IdentityRole<int>, WebDbContext, int>()
        .EnableTokenEndpoint("/api/customauth/login")
        .AllowPasswordFlow()
        .UseJsonWebTokens()
        .AddSigningCertificate(c);

Если я отключу UseJsonWebTokens(), я могу сгенерировать токен и успешно авторизоваться. Однако я не уверен, что мой сертификат проверяет возвращенные токены.

А при включении UseJsonWebTokens я могу выдать токен JWT в этой конечной точке. Однако я не могу подтвердить подлинность любого запроса!

Я использую следующий код в конфигурации приложения:

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        RequireHttpsMetadata = false,
        Authority = "http://localhost:60000/",
        Audience = "http://localhost:60000/",
    });
    app.UseOAuthValidation();
    app.UseIdentity();
    app.UseOpenIddict();
    app.UseMvcWithDefaultRoute();
  • Как я могу заставить запрос быть проверенным с моим сертификатом, чтобы убедиться, что токен JWT не подделан.
  • Каковы правильные настройки, которые позволят проверять и авторизовать мой токен JWT, учитывая, что если я не использую JWT, я получаю авторизацию успешно.

1 ответ

Решение

Если я отключу UseJsonWebTokens(), я могу сгенерировать токен и успешно авторизоваться. Однако я не уверен, что мой сертификат проверяет возвращенные токены.

В ASOS (серверная структура OpenID Connect за OpenIddict) есть 2 различных встроенных механизма сериализации для создания и защиты токенов:

  • Тот, который использует IdentityModel (библиотека, разработанная Microsoft) и производит стандартные токены, проверяемые третьими сторонами:

Идентификационные токены (по определению JWT) всегда создаются с использованием этого процесса, и вы можете вызвать UseJsonWebTokens() заставить OpenIddict выдавать токены доступа, которые используют тот же процесс сериализации.

Сертификат, который вы указываете при звонке AddSigningCertificate() всегда используется для подписи этих токенов.

  • Тот, который использует стек ASP.NET Core Data Protection (также разработанный Microsoft):

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

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

В этом случае сертификат вы указываете при звонке AddSigningCertificate() не используется

Вместо этого эти токены всегда шифруются стеком защиты данных с использованием Authenticated Encryption алгоритм (по умолчанию AES-256-CBC с HMACSHA256), обеспечивающий подлинность, целостность и конфиденциальность. Для этого 2 ключа (один для шифрования, один для проверки) выводятся из стека защиты данных из одного из главных ключей, хранящихся в кольце ключей.

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

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

Создать аутентификацию на основе токена JWT в ASP.NET Core очень просто. Пожалуйста, перейдите по ссылке ниже, чтобы получить больше информации. Как создать токен JWT в Asp NET Core

Образец кода

public static class AuthenticationConfig
{
    public static string GenerateJSONWebToken(string user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[] {
             new Claim("UserName", user),
              new Claim("Role", "1"),
                };

        var token = new JwtSecurityToken("http://localhost:30972",
          "http://localhost:30972",
          claims,
          DateTime.UtcNow,
          expires: DateTime.Now.AddMinutes(10),
          signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    //ConfigureJwtAuthentication
    internal static TokenValidationParameters tokenValidationParams;
    public static void ConfigureJwtAuthentication(this IServiceCollection services)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        tokenValidationParams = new TokenValidationParameters()
        {
            ValidateIssuerSigningKey = true,
            ValidIssuer = "http://localhost:30972",
            ValidateLifetime = true,
            ValidAudience = "http://localhost:30972",
            ValidateAudience = true,
            RequireSignedTokens = true,
            // Use our signing credentials key here
            // optionally we can inject an RSA key as
            //IssuerSigningKey = new RsaSecurityKey(rsaParams),
            IssuerSigningKey = credentials.Key,
            ClockSkew = TimeSpan.FromMinutes(10)
        };
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })

        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = tokenValidationParams;
            #if PROD || UAT
                  options.IncludeErrorDetails = false;
            #elif DEBUG
                  options.RequireHttpsMetadata = false;
            #endif
        });
    }
}

Добавьте эту строку в Startup.cs

 public void ConfigureServices(IServiceCollection services)
    {
        services.ConfigureJwtAuthentication();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new  AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

Добавьте эти строки в Контроллер аутентификации

[Route("api/[controller]")]
public class AuthenticationController : Controller
{
    // GET: api/<controller>
    [HttpGet]
    public string Get(string user, string pass)
    {
        if (user == "admin")
        {
            return AuthenticationConfig.GenerateJSONWebToken(user);
        }
        else
        {
            return "";
        }

    }


    // POST api/<controller>
    [Authorize]
    [HttpPost]
    public string Post()
    {
        var identity = HttpContext.User.Identity as ClaimsIdentity;
        IEnumerable<Claim> claim = identity.Claims;
        var UserName = claim.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();

        return "Welcome to " + UserName + "!";
    }


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