refactor: separate the method of counting failed attempts
This commit is contained in:
parent
8c51ba83a4
commit
71c31c0bbb
@ -24,6 +24,7 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
|||||||
|
|
||||||
private static string GetAuthCacheKey(string fingerprint) => $"{fingerprint}_auth_token";
|
private static string GetAuthCacheKey(string fingerprint) => $"{fingerprint}_auth_token";
|
||||||
private static string GetFirstAuthCacheKey(string fingerprint) => $"{fingerprint}_auth_token_first";
|
private static string GetFirstAuthCacheKey(string fingerprint) => $"{fingerprint}_auth_token_first";
|
||||||
|
private static string GetAttemptFailedCountKey(string fingerprint) => $"{fingerprint}_login_failed";
|
||||||
|
|
||||||
private Task SetAuthTokenDataToCache(AuthToken data, CancellationToken cancellation) =>
|
private Task SetAuthTokenDataToCache(AuthToken data, CancellationToken cancellation) =>
|
||||||
cache.SetAsync(
|
cache.SetAsync(
|
||||||
@ -47,34 +48,47 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
|||||||
private Task RevokeAccessToken(string token) =>
|
private Task RevokeAccessToken(string token) =>
|
||||||
revokedToken.AddTokenToRevokedAsync(token, accessTokenService.GetExpireDateTime(token));
|
revokedToken.AddTokenToRevokedAsync(token, accessTokenService.GetExpireDateTime(token));
|
||||||
|
|
||||||
private async Task VerifyUserOrThrowError(RequestContextInfo requestContext, User user, string password, string username,
|
private async Task RecordFailedLoginAttempt(string fingerprint, string userId, CancellationToken cancellation)
|
||||||
CancellationToken cancellation = default)
|
|
||||||
{
|
{
|
||||||
if ((user.Email.Equals(username, StringComparison.OrdinalIgnoreCase) || user.Username.Equals(username, StringComparison.OrdinalIgnoreCase)) &&
|
var failedLoginAttemptsCount = await cache.GetAsync<int?>(GetAttemptFailedCountKey(fingerprint), cancellation) ?? 1;
|
||||||
passwordService.VerifyPassword(password, user.Salt, user.PasswordHash))
|
var failedLoginCacheExpiration = TimeSpan.FromHours(1);
|
||||||
return;
|
|
||||||
|
|
||||||
var failedLoginCacheName = $"{requestContext.Fingerprint}_login_failed";
|
if (failedLoginAttemptsCount > 5)
|
||||||
var countFailedLogin = await cache.GetAsync<int?>(failedLoginCacheName, cancellation) ?? 1;
|
|
||||||
var cacheSaveTime = TimeSpan.FromHours(1);
|
|
||||||
|
|
||||||
await cache.SetAsync(failedLoginCacheName, countFailedLogin + 1, slidingExpiration: cacheSaveTime, cancellationToken: cancellation);
|
|
||||||
|
|
||||||
if (countFailedLogin > 5)
|
|
||||||
{
|
{
|
||||||
logger.LogWarning(
|
logger.LogWarning(
|
||||||
"Multiple unsuccessful login attempts for user ID {UserId}. Attempt count: {AttemptNumber}.",
|
"Multiple unsuccessful login attempts for user ID {UserId}. Fingerprint: {Fingerprint}. Attempt count: {AttemptNumber}.",
|
||||||
user.Id,
|
userId,
|
||||||
countFailedLogin);
|
fingerprint,
|
||||||
|
failedLoginAttemptsCount);
|
||||||
|
|
||||||
throw new SecurityException("Too many unsuccessful login attempts. Please try again later.");
|
throw new SecurityException("Too many unsuccessful login attempts. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"Login attempt failed for user ID {UserId}. Fingerprint: {Fingerprint}. Attempt count: {AttemptNumber}.",
|
"Login attempt failed for user ID {UserId}. Fingerprint: {Fingerprint}. Attempt count: {AttemptNumber}.",
|
||||||
user.Id,
|
userId,
|
||||||
requestContext.Fingerprint,
|
fingerprint,
|
||||||
countFailedLogin);
|
failedLoginAttemptsCount);
|
||||||
|
|
||||||
|
await cache.SetAsync(GetAttemptFailedCountKey(fingerprint), failedLoginAttemptsCount + 1,
|
||||||
|
slidingExpiration: failedLoginCacheExpiration, cancellationToken: cancellation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ResetFailedLoginAttempts(string fingerprint, CancellationToken cancellation) =>
|
||||||
|
cache.RemoveAsync(GetAttemptFailedCountKey(fingerprint), cancellation);
|
||||||
|
|
||||||
|
private async Task VerifyUserOrThrowError(RequestContextInfo requestContext, User user, string password, string username,
|
||||||
|
CancellationToken cancellation = default)
|
||||||
|
{
|
||||||
|
if ((user.Email.Equals(username, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
user.Username.Equals(username, StringComparison.OrdinalIgnoreCase)) &&
|
||||||
|
passwordService.VerifyPassword(password, user.Salt, user.PasswordHash))
|
||||||
|
{
|
||||||
|
await ResetFailedLoginAttempts(requestContext.Fingerprint, cancellation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RecordFailedLoginAttempt(requestContext.Fingerprint, user.Id, cancellation);
|
||||||
|
|
||||||
throw new SecurityException("Authentication failed. Please check your credentials.");
|
throw new SecurityException("Authentication failed. Please check your credentials.");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user