Anonymous
Получение HTTP 400 при попытке использовать токен обновления для аутентификации API
Сообщение
Anonymous » 05 сен 2025, 04:32
Проблема: механизм токена обновления не работает, когда срок действия токена истек. Обновить
токен запросить новый токен доступа и продолжить без перерыва < /p>
mobile < /strong> < /p>
Код: Выделить всё
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
protected override async void OnStart()
{
await GetValidAccessToken();
}
protected override async void OnResume()
{
await GetValidAccessToken();
}
public class TokenResponse
{
[JsonPropertyName("AccessToken")]
public string Token { get; set; }
[JsonPropertyName("RefreshToken")]
public string RefreshToken { get; set; }
}
private async Task GetValidAccessToken()
{
try
{
var accessToken = await SecureStorage.GetAsync("AuthToken");
var refreshToken = await SecureStorage.GetAsync("RefreshToken");
var email = await SecureStorage.GetAsync("UserEmail");
using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) })
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var requestUri = "/api/v1/Users/all";
var response = await httpClient.GetAsync(requestUri);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var refreshData = new MultipartFormDataContent();
refreshData.Add(new StringContent(refreshToken), "refreshToken");
response = await httpClient.PostAsync("/api/v1/UserAuth/RefreshToken", refreshData);
if (!response.IsSuccessStatusCode)
throw new Exception("Failed to refresh token.");
var rawContent = await response.Content.ReadAsStringAsync();
using (var stringReader = new StringReader(rawContent))
{
using (var jsonReader = new JsonTextReader(stringReader))
{
var tokenResponse = Newtonsoft.Json.JsonSerializer.Create().Deserialize(jsonReader);
if (tokenResponse == null)
throw new Exception("Failed to parse token response.");
await SecureStorage.SetAsync("AuthToken", "null");
await SecureStorage.SetAsync("RefreshToken", "null");
await SecureStorage.SetAsync("AuthToken", tokenResponse.Token);
await SecureStorage.SetAsync("RefreshToken", tokenResponse.RefreshToken);
var savedAuthToken = await SecureStorage.GetAsync("AuthToken");
var savedRefreshToken = await SecureStorage.GetAsync("RefreshToken");
await UpdateTokensInDatabase(email, tokenResponse.RefreshToken);
if (savedAuthToken != tokenResponse.Token || savedRefreshToken != tokenResponse.RefreshToken)
throw new Exception("Tokens not updated properly.");
}
}
}
else
throw new Exception($"Request failed with status code: {response.StatusCode}");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private async Task GetValidAccessTokenAsync()
{
var accessToken = await SecureStorage.GetAsync("AuthToken");
if (string.IsNullOrEmpty(accessToken) || IsTokenExpired(accessToken))
{
var refreshToken = await SecureStorage.GetAsync("RefreshToken");
if (!string.IsNullOrEmpty(refreshToken))
{
var newToken = await RefreshAccessTokenAsync(refreshToken);
if (!string.IsNullOrEmpty(newToken))
{
await SecureStorage.SetAsync("AuthToken", newToken);
return newToken;
}
}
return null;
}
return accessToken;
}
private bool IsTokenExpired(string token)
{
try
{
var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(token);
return jwt.ValidTo < DateTime.UtcNow.AddMinutes(1);
}
catch
{
return true;
}
}
private async Task RefreshAccessTokenAsync(string refreshToken)
{
using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) })
{
var content = new MultipartFormDataContent();
content.Add(new StringContent(refreshToken), "refreshToken");
var response = await httpClient.PostAsync("/api/v1/UserAuth/RefreshToken", content);
if (response.IsSuccessStatusCode)
{
var rawContent = await response.Content.ReadAsStringAsync();
var tokenResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(rawContent);
if (tokenResponse != null && !string.IsNullOrEmpty(tokenResponse.Token))
{
if (!string.IsNullOrEmpty(tokenResponse.RefreshToken))
await SecureStorage.SetAsync("RefreshToken", tokenResponse.RefreshToken);
return tokenResponse.Token;
}
}
}
return null;
}
private async Task UpdateTokensInDatabase(string email, string refreshToken)
{
string accessToken = await GetValidAccessTokenAsync();
if (string.IsNullOrEmpty(accessToken))
{
await ShowAlertAsync("Session expired", "Please log in again.", "OK");
return;
}
using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) })
{
var tokenUpdateData = new MultipartFormDataContent();
tokenUpdateData.Add(new StringContent(email), "email");
tokenUpdateData.Add(new StringContent(refreshToken), "refreshToken");
var response = await httpClient.PostAsync("/api/v1/UserAuth/UpdateTokens", tokenUpdateData);
if (!response.IsSuccessStatusCode)
throw new Exception("Failed to update tokens in the database.");
}
api [/b]
Код: Выделить всё
[HttpPost("RegisterUser")]
public async Task RegisterUser([FromForm] UserRegistrationRequest userRegistrationRequest)
{
try
{
UsersEntity user = await _usersRepository.FindByEmailAsync(userRegistrationRequest.Email);
if (user == null)
{
user = new UsersEntity
{
UserName = userRegistrationRequest.Name + "User",
Name = userRegistrationRequest.Name,
Email = userRegistrationRequest.Email,
Role = "User",
Groups = "[]",
Created_by = "System",
Created_date = DateTimeOffset.UtcNow.Date,
Images = null,
Number = userRegistrationRequest.Number,
ImagesId = userRegistrationRequest.Image_id,
DeviceToken = userRegistrationRequest.DeviceToken ?? null,
Point = 0,
Modified_by = userRegistrationRequest.Name,
IdentityId = Guid.NewGuid().ToString(),
};
var registerUser = await _signInManager.UserManager.CreateAsync(user);
if (!registerUser.Succeeded)
return BadRequest(registerUser.Errors);
var addPassword = await _signInManager.UserManager.AddPasswordAsync(user, userRegistrationRequest.Password);
if (addPassword.Succeeded == false) return BadRequest(addPassword.Errors);
return Ok("User registered successfully");
}
return Ok(user);
}
catch (Exception ex)
{
return BadRequest($"An error occurred: {ex.Message}");
}
}
[HttpPost("Login")]
public async Task Login([FromForm] string email, [FromForm] string password)
{
if (string.IsNullOrEmpty(email))
return BadRequest("Email cannot be empty.");
if (string.IsNullOrEmpty(password))
return BadRequest("Password cannot be empty.");
var user = await _usersRepository.FindByEmailAsync(email);
if (user == null) return NotFound("User Not Found or Password Invalid");
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false);
if (signInResult.Succeeded == false) return NotFound("User Not Found or Password Invalid");
var token = CreateToken(user);
var refreshToken = GenerateRefreshToken();
user.RefreshToken = refreshToken;
user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(7);
await _usersRepository.UpdateAsync(user);
return Ok(new
{
Token = token,
RefreshToken = refreshToken
});
}
private string CreateToken(UsersEntity user)
{
var claims = new List
{
new(ClaimTypes.Name, user.UserName),
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var Sectoken = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Audience"],
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
var token = new JwtSecurityTokenHandler().WriteToken(Sectoken);
return token;
}
private string GenerateRefreshToken()
{
var randomBytes = new byte[64];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomBytes);
}
return Convert.ToBase64String(randomBytes);
}
[HttpPost("RefreshToken")]
public async Task RefreshToken([FromForm] string refreshToken)
{
try
{
var user = await _usersRepository.FindByRefreshTokenAsync(refreshToken);
if (user == null || user.RefreshToken != refreshToken || user.RefreshTokenExpiryTime
Подробнее здесь: [url]https://stackoverflow.com/questions/79756352/getting-http-400-when-attempting-to-use-refresh-token-for-api-authentication[/url]
1757035936
Anonymous
Проблема: механизм токена обновления не работает, когда срок действия токена истек. Обновить токен запросить новый токен доступа и продолжить без перерыва < /p> [b] mobile < /strong> < /p> [code] public App() { InitializeComponent(); MainPage = new AppShell(); } protected override async void OnStart() { await GetValidAccessToken(); } protected override async void OnResume() { await GetValidAccessToken(); } public class TokenResponse { [JsonPropertyName("AccessToken")] public string Token { get; set; } [JsonPropertyName("RefreshToken")] public string RefreshToken { get; set; } } private async Task GetValidAccessToken() { try { var accessToken = await SecureStorage.GetAsync("AuthToken"); var refreshToken = await SecureStorage.GetAsync("RefreshToken"); var email = await SecureStorage.GetAsync("UserEmail"); using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) }) { httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var requestUri = "/api/v1/Users/all"; var response = await httpClient.GetAsync(requestUri); if (response.StatusCode == HttpStatusCode.Unauthorized) { var refreshData = new MultipartFormDataContent(); refreshData.Add(new StringContent(refreshToken), "refreshToken"); response = await httpClient.PostAsync("/api/v1/UserAuth/RefreshToken", refreshData); if (!response.IsSuccessStatusCode) throw new Exception("Failed to refresh token."); var rawContent = await response.Content.ReadAsStringAsync(); using (var stringReader = new StringReader(rawContent)) { using (var jsonReader = new JsonTextReader(stringReader)) { var tokenResponse = Newtonsoft.Json.JsonSerializer.Create().Deserialize(jsonReader); if (tokenResponse == null) throw new Exception("Failed to parse token response."); await SecureStorage.SetAsync("AuthToken", "null"); await SecureStorage.SetAsync("RefreshToken", "null"); await SecureStorage.SetAsync("AuthToken", tokenResponse.Token); await SecureStorage.SetAsync("RefreshToken", tokenResponse.RefreshToken); var savedAuthToken = await SecureStorage.GetAsync("AuthToken"); var savedRefreshToken = await SecureStorage.GetAsync("RefreshToken"); await UpdateTokensInDatabase(email, tokenResponse.RefreshToken); if (savedAuthToken != tokenResponse.Token || savedRefreshToken != tokenResponse.RefreshToken) throw new Exception("Tokens not updated properly."); } } } else throw new Exception($"Request failed with status code: {response.StatusCode}"); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } private async Task GetValidAccessTokenAsync() { var accessToken = await SecureStorage.GetAsync("AuthToken"); if (string.IsNullOrEmpty(accessToken) || IsTokenExpired(accessToken)) { var refreshToken = await SecureStorage.GetAsync("RefreshToken"); if (!string.IsNullOrEmpty(refreshToken)) { var newToken = await RefreshAccessTokenAsync(refreshToken); if (!string.IsNullOrEmpty(newToken)) { await SecureStorage.SetAsync("AuthToken", newToken); return newToken; } } return null; } return accessToken; } private bool IsTokenExpired(string token) { try { var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler(); var jwt = handler.ReadJwtToken(token); return jwt.ValidTo < DateTime.UtcNow.AddMinutes(1); } catch { return true; } } private async Task RefreshAccessTokenAsync(string refreshToken) { using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) }) { var content = new MultipartFormDataContent(); content.Add(new StringContent(refreshToken), "refreshToken"); var response = await httpClient.PostAsync("/api/v1/UserAuth/RefreshToken", content); if (response.IsSuccessStatusCode) { var rawContent = await response.Content.ReadAsStringAsync(); var tokenResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(rawContent); if (tokenResponse != null && !string.IsNullOrEmpty(tokenResponse.Token)) { if (!string.IsNullOrEmpty(tokenResponse.RefreshToken)) await SecureStorage.SetAsync("RefreshToken", tokenResponse.RefreshToken); return tokenResponse.Token; } } } return null; } private async Task UpdateTokensInDatabase(string email, string refreshToken) { string accessToken = await GetValidAccessTokenAsync(); if (string.IsNullOrEmpty(accessToken)) { await ShowAlertAsync("Session expired", "Please log in again.", "OK"); return; } using (var httpClient = new HttpClient { BaseAddress = new Uri(AppSettings.UrlApi) }) { var tokenUpdateData = new MultipartFormDataContent(); tokenUpdateData.Add(new StringContent(email), "email"); tokenUpdateData.Add(new StringContent(refreshToken), "refreshToken"); var response = await httpClient.PostAsync("/api/v1/UserAuth/UpdateTokens", tokenUpdateData); if (!response.IsSuccessStatusCode) throw new Exception("Failed to update tokens in the database."); } [/code] api [/b] [code][HttpPost("RegisterUser")] public async Task RegisterUser([FromForm] UserRegistrationRequest userRegistrationRequest) { try { UsersEntity user = await _usersRepository.FindByEmailAsync(userRegistrationRequest.Email); if (user == null) { user = new UsersEntity { UserName = userRegistrationRequest.Name + "User", Name = userRegistrationRequest.Name, Email = userRegistrationRequest.Email, Role = "User", Groups = "[]", Created_by = "System", Created_date = DateTimeOffset.UtcNow.Date, Images = null, Number = userRegistrationRequest.Number, ImagesId = userRegistrationRequest.Image_id, DeviceToken = userRegistrationRequest.DeviceToken ?? null, Point = 0, Modified_by = userRegistrationRequest.Name, IdentityId = Guid.NewGuid().ToString(), }; var registerUser = await _signInManager.UserManager.CreateAsync(user); if (!registerUser.Succeeded) return BadRequest(registerUser.Errors); var addPassword = await _signInManager.UserManager.AddPasswordAsync(user, userRegistrationRequest.Password); if (addPassword.Succeeded == false) return BadRequest(addPassword.Errors); return Ok("User registered successfully"); } return Ok(user); } catch (Exception ex) { return BadRequest($"An error occurred: {ex.Message}"); } } [HttpPost("Login")] public async Task Login([FromForm] string email, [FromForm] string password) { if (string.IsNullOrEmpty(email)) return BadRequest("Email cannot be empty."); if (string.IsNullOrEmpty(password)) return BadRequest("Password cannot be empty."); var user = await _usersRepository.FindByEmailAsync(email); if (user == null) return NotFound("User Not Found or Password Invalid"); var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false); if (signInResult.Succeeded == false) return NotFound("User Not Found or Password Invalid"); var token = CreateToken(user); var refreshToken = GenerateRefreshToken(); user.RefreshToken = refreshToken; user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(7); await _usersRepository.UpdateAsync(user); return Ok(new { Token = token, RefreshToken = refreshToken }); } private string CreateToken(UsersEntity user) { var claims = new List { new(ClaimTypes.Name, user.UserName), new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), }; var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var Sectoken = new JwtSecurityToken(_config["Jwt:Issuer"], _config["Jwt:Audience"], claims, expires: DateTime.Now.AddMinutes(120), signingCredentials: credentials); var token = new JwtSecurityTokenHandler().WriteToken(Sectoken); return token; } private string GenerateRefreshToken() { var randomBytes = new byte[64]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(randomBytes); } return Convert.ToBase64String(randomBytes); } [HttpPost("RefreshToken")] public async Task RefreshToken([FromForm] string refreshToken) { try { var user = await _usersRepository.FindByRefreshTokenAsync(refreshToken); if (user == null || user.RefreshToken != refreshToken || user.RefreshTokenExpiryTime Подробнее здесь: [url]https://stackoverflow.com/questions/79756352/getting-http-400-when-attempting-to-use-refresh-token-for-api-authentication[/url]