Как заставить ASP.NET Core JWT Bearer Authentication сначала проверять заголовок авторизации, а затем проверять файлы coC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как заставить ASP.NET Core JWT Bearer Authentication сначала проверять заголовок авторизации, а затем проверять файлы co

Сообщение Anonymous »

Чтобы дать вам некоторый контекст:
Я пытаюсь реализовать безопасность аутентификации по токену обновления/доступа для простого веб-API с использованием ASPNET Core. Пока все идет хорошо.. Это работает! Просто не так, как ожидалось.
Насколько я понимаю, при такой настройке первое, что приложение должно проверять, — это JwtBearer в рамках аутентификации. В этом случае токен доступа, который будет отправлен в заголовке.

Код: Выделить всё

builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["JWT:Issuer"], // Ensure this matches your token's Issuer
ValidateAudience = false, // Assuming you're not validating audience, change if necessary
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]!)),
ValidateLifetime = true, // Ensure lifetime validation is enabled
ClockSkew = TimeSpan.Zero // Optional: set this to zero to remove any time drift
};

options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// Check if the "auth_token" cookie is present and extract the token
if (context.Request.Cookies.ContainsKey("auth_token"))
{
context.Token = context.Request.Cookies["auth_token"];
}
return Task.CompletedTask;
}
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"));
options.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));
});
Теперь логика работы безопасности в этом приложении следующая:
Каждый запрос будет проверяться на наличие заголовка (токена доступа), который будет иметь короткий срок службы. Каждые несколько минут на стороне клиента (React) будет выполняться useEffect, который попытается повторно получить указанный токен доступа с использованием следующей конечной точки:

Код: Выделить всё

 [HttpGet]
public async Task RefreshAccessToken()
{
// Access HttpContext from the ControllerBase class (no need to pass it as a parameter)
if (!HttpContext.Request.Cookies.ContainsKey("auth_token"))
return StatusCode(401, "Unauthorized");

var token = HttpContext.Request.Cookies["auth_token"];

// Decode the JWT to extract claims
var decodedClaims = _refreshTokenServices.DecodeJWT(token!);

if (decodedClaims == null)
return StatusCode(401, "Unauthorized");

// Retrieve the username claim from the decoded JWT
var usernameClaim = decodedClaims?.FindFirst(JwtRegisteredClaimNames.Sub);

// Check if the username claim exists
if (usernameClaim == null)
return StatusCode(401, "Unauthorized");

var username = usernameClaim.Value;  // Use the 'Value' to get the actual username

// Find the user by username
var foundUser = await _userManager.FindByNameAsync(username);

// If user is not found, return unauthorized
if (foundUser == null)
return StatusCode(401, "Unauthorized");

// Create a new access token for the user
var accessToken = _accessTokenServices.CreateToken(foundUser);

// Return the new access token
return Ok(new { AccessToken = accessToken.Result });
}
Теперь я также буду заполнять каждый вызов API-выборки RefreshAccessToken, который будет вызываться, когда код статуса будет 401. И он просто ничего не сделает и вернет ошибку, если его 403. Значение в в случае сбоя повторной выборки или чего-то еще, все вызовы API из внешнего интерфейса будут безопасными.
Теперь я разобрался с этой стороной логики. Но дело в том, почему-то. Эта структура полностью игнорирует токен носителя.
Проведя некоторое тестирование, я заметил, что она проверяет только HttpOnly, что означает токен обновления.
Так как указанный токен обновления содержит только имя пользователя и информацию об идентификаторе.
Это бесполезно для стороны управления доступом на основе ролей в приложении. Что мне кажется странным, так это то, что если я полностью удалю токен обновления, то есть не будет ни одного файла cookie HttpOnly, только тогда он удосужится проверить токен носителя. Теперь я знаю, что это, вероятно, связано с неправильным использованием или неправильной конфигурацией с моей стороны, но Я понятия не имею, как действовать.
Я пытаюсь использовать атрибуты для обработки моих защищенных маршрутов следующим образом:

Код: Выделить всё

 [HttpGet]
[Route("admin-test")]
[Authorize(Roles = "Admin")]
public IActionResult Admin()
{
return Ok("Admin");
}
Я видел несколько руководств, и они говорят, что нужно сделать что-то вроде Request.Header и просто проверить заголовок на наличие правильного токена. Но я действительно хочу реализовать эту функциональность с использованием атрибутов, поскольку считаю, что они выглядят чище, но если единственный способ реализовать проверку подлинности/авторизации обновления/доступа — без нее, пусть будет так.
Любые рекомендации или советы по реализации этой функции будут высоко оценены!
РЕДАКТИРОВАТЬ: В случае необходимости я отправляю файлы cookie обратно следующим образом:

Код: Выделить всё

 [HttpPost]
[Route("login")]
public async Task Login([FromBody] LoginRequestDto loginModel)
{
if (!ModelState.IsValid) return BadRequest("Invalid Input Data");
var user = await _userManager.Users.FirstOrDefaultAsync(u => u.UserName == loginModel.Username);
if (user == null) return BadRequest("Wrong Username or Password");
var passwordMatch = await _userManager.CheckPasswordAsync(user, loginModel.Password);
if (!passwordMatch) return BadRequest("Wrong Username or Password");
var refreshToken = _refreshToken.CreateToken(user);
Response.Cookies.Append("auth_token", refreshToken, new CookieOptions()
{
HttpOnly = true,
SameSite = SameSiteMode.None,
Secure = false,  //For dev purposes
Expires = DateTime.Now.AddDays(7)
});
var accessToken = _accessToken.CreateToken(user);
return Ok(new { AcessToken = accessToken.Result });
}
}
И вот как создаются токены:

Код: Выделить всё

   public async Task CreateToken(Usuario usuario)
{
var userRoles = await _userManager.GetRolesAsync(usuario);
var authClaims = new List()
{
new Claim(JwtRegisteredClaimNames.Sub, usuario.UserName!),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
authClaims.AddRange(userRoles.Select(role => new Claim(ClaimTypes.Role, role)));

// Ensure the expiration time is UTC to avoid any timezone issues
var expiresAt = DateTime.UtcNow.AddMinutes(15);

var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature);

var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(authClaims),
Expires = expiresAt, // Set expiration time
IssuedAt = DateTime.UtcNow, // Set the issue time
NotBefore = DateTime.UtcNow.AddSeconds(5), // Set the 'NotBefore' to a few seconds after issue time
SigningCredentials = creds,
Issuer = _config["JWT:Issuer"]
};

var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
Единственное различие между токеном доступа и токеном обновления — это продолжительность и утверждения. Доступ содержит роли пользователя, тогда как токен обновления содержит только информацию о самом пользователе, например имя пользователя и его идентификатор.

Подробнее здесь: https://stackoverflow.com/questions/793 ... tion-heade
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Как заставить ASP.NET Core JWT Bearer Authentication сначала проверять заголовок авторизации, а затем проверять файлы co
    Anonymous » » в форуме C#
    0 Ответы
    45 Просмотры
    Последнее сообщение Anonymous
  • Как заставить ASP.NET Core JWT Bearer Authentication сначала проверять заголовок авторизации, а затем проверять файлы co
    Anonymous » » в форуме C#
    0 Ответы
    28 Просмотры
    Последнее сообщение Anonymous
  • Как изменить token_type с «bearer» на «bearer» в ответе Keycloak/token?
    Anonymous » » в форуме JAVA
    0 Ответы
    23 Просмотры
    Последнее сообщение Anonymous
  • Как изменить token_type с «bearer» на «bearer» в ответе Keycloak/token?
    Anonymous » » в форуме JAVA
    0 Ответы
    17 Просмотры
    Последнее сообщение Anonymous
  • ASP.NET Core 7 Identity + JWT Authentication работает неправильно
    Anonymous » » в форуме C#
    0 Ответы
    34 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»