JWT TokenValidationParameters проблема с ValidAudiences

#asp.net-core #jwt #asp.net-core-webapi

#asp.net-ядро #jwt #asp.net-core-webapi

Вопрос:

Я использую JWT в ASP.NET Основной веб-api (.NET Core 3.1) с Microsoft.AspNetCore.Идентификация. У меня есть два проекта, настроенных следующим образом:

MyProj.Идентификатор и MyProj.Server. Я определил 2 роли: «администратор» и «пользователь». Я хотел бы авторизовать вызовы контроллеров MyProj.Server с помощью токенов, сгенерированных MyProj.Идентификация для пользователей в роли «пользователь». Я также хотел бы разрешить некоторые вызовы MyProj.Идентификация с токенами, сгенерированными MyProj.Идентификация пользователей в роли «администратор». В MyProj.У меня есть следующий контроллер:

 namespace MyProj.Identity.Controllers
{
    [ApiController]
    [Route("api/authentication")]
    public class AuthenticationController : ControllerBase
    {           
        //...
        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginDto model)
        {
            //...
        }
        
        [Authorize(Roles = UserRoles.Admin)]
        [HttpPost("register")]
        public async Task<IActionResult> Register([FromBody] RegistrationInfo registrationInput)
        {
            //...
        }
        
        [Authorize(Roles = UserRoles.Admin)]
        [HttpPost("register-admin")]
        public async Task<IActionResult> RegisterAdmin([FromBody] RegistrationInfo registrationInput)
        {
            //...
        }
    }
}
  

В MyProj.Server есть контроллеры, подобные следующим:

 namespace MyProj.Server.Controllers
{
    [Authorize(Roles = UserRoles.User)]
    [ApiController]
    [Route("api/items")]
    public class MyController : ControllerBase
    {
        //...
        [HttpGet]
        public async Task<ActionResult<IEnumerable<ItemDto>>> Get()
        {
            //...
        }
        //...
    }
}
  

Запуск в обоих проектах имеет следующую конфигурацию

Запуск

 public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })

    // Adding Jwt Bearer  
    .AddJwtBearer(options =>
    {
        options.SaveToken = true;
        options.RequireHttpsMetadata = false;
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["JWT:ValidIssuer"],
            ValidAudiences = Configuration.GetSection("JWT:ValidAudiences").Get<string[]>(),
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
        };
        options.Events = new JwtBearerEvents
        {
            OnAuthenticationFailed = context =>
            {
                if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                {
                    context.Response.Headers.Add("Token-Expired", "true");
                }
                return Task.CompletedTask;
            }
        };
    });
    //...
}
  

В appsettings.json для обоих проектов есть:

 "JWT": {
    "ValidIssuer": "http://MyProj.Identity.Url",
    "ValidAudiences": [
      "http://MyProj.Identity.Url",
      "http://MyProj.Server.Url" 
    ],
    "Secret": "MySecret",
    "TokenExpiryMinutes": "120"
  }
  

Проблема, с которой я сталкиваюсь, заключается в том, что когда я устанавливаю свойство ValidAudiences в TokenValidationParameters, токен, который генерируется при входе в систему, не имеет никакого набора «aud» (проверяя его с помощью https://jwt.io /) и, как следствие, авторизация не выполняется. Если вместо этого я установлю свойство ValidAudience (одна аудитория), все работает нормально, но я не могу авторизовать более одной аудитории. Я попытался установить свойство «ValidAudiences» вручную также из списка (не из конфигурации), но результат был тот же. Кажется, я что-то упускаю в отношении нескольких допустимых аудиторий. Любые идеи будут оценены.

Ответ №1:

Решение было прямо передо мной :).

Метод входа в систему в MyProj.Идентификатор (который генерирует токен) должен включать утверждения аутентификации для каждой из аудиторий следующим образом:

 namespace MyProj.Identity.Controllers
{
    [ApiController]
    [Route("api/authentication")]
    public class AuthenticationController : ControllerBase
    {
        // ...
        
        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginDto model)
        {
            // ...
            foreach (var audience in _configuration.GetSection("JWT:ValidAudiences").Get<string[]>())
            {
                authClaims.Add(new Claim(JwtRegisteredClaimNames.Aud, audience));
            }
            // ...
            var token = new JwtSecurityToken(
                issuer: _configuration["JWT:ValidIssuer"],
                expires: DateTime.Now.AddMinutes(int.Parse(_configuration["JWT:TokenExpiryMinutes"])),
                claims: authClaims,
                signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256));
        }
        // ...
    }
}
  

Это решает проблему.