diff --git a/serene/src/Serene.Web/Modules/Common/AppServices/UserPasswordValidator.cs b/serene/src/Serene.Web/Modules/Common/AppServices/UserPasswordValidator.cs index a0e1c6a574..063e0e0015 100644 --- a/serene/src/Serene.Web/Modules/Common/AppServices/UserPasswordValidator.cs +++ b/serene/src/Serene.Web/Modules/Common/AppServices/UserPasswordValidator.cs @@ -122,7 +122,7 @@ bool validatePassword() => UserHelper.CalculateHash(password, user.PasswordSalt) uow.Commit(); - userRetriever.InvalidateItem(user, cache); + userRetriever.RemoveCachedUser(user, cache); return PasswordValidationResult.Valid; } @@ -183,8 +183,7 @@ private PasswordValidationResult ValidateFirstTimeUser(ref string username, stri uow.Commit(); - userRetriever.InvalidateById(userId.ToInvariant(), cache); - userRetriever.InvalidateByUsername(username, cache); + userRetriever.RemoveCachedUser(userId.ToInvariant(), username, cache); return PasswordValidationResult.Valid; } diff --git a/serene/src/Serene.Web/Modules/Common/AppServices/UserRetrieveService.cs b/serene/src/Serene.Web/Modules/Common/AppServices/UserRetrieveService.cs index 24740e08d0..3a54ad97cd 100644 --- a/serene/src/Serene.Web/Modules/Common/AppServices/UserRetrieveService.cs +++ b/serene/src/Serene.Web/Modules/Common/AppServices/UserRetrieveService.cs @@ -3,7 +3,7 @@ namespace Serene.AppServices; -public class UserRetrieveService(ITwoLevelCache cache, ISqlConnections sqlConnections) : IUserRetrieveService, IUserCacheInvalidator +public class UserRetrieveService(ITwoLevelCache cache, ISqlConnections sqlConnections) : IUserRetrieveService, IRemoveAll, IRemoveCachedUser { protected readonly ITwoLevelCache cache = cache ?? throw new ArgumentNullException(nameof(cache)); protected readonly ISqlConnections sqlConnections = sqlConnections ?? throw new ArgumentNullException(nameof(cache)); @@ -52,30 +52,16 @@ public IUserDefinition ByUsername(string username) }); } - public void InvalidateAll() + public void RemoveAll() { cache.ExpireGroupItems(MyRow.Fields.GenerationKey); } - public void InvalidateById(string userId) - { - if (userId == null || - !int.TryParse(userId, CultureInfo.InvariantCulture, out int id)) - return; - cache.Remove("UserByID_" + id.ToInvariant()); - } - - public void InvalidateByUsername(string username) + public void RemoveCachedUser(string userId, string username) { + if (userId != null && int.TryParse(userId, CultureInfo.InvariantCulture, out int id)) + cache.Remove("UserByID_" + id.ToInvariant()); if (username != null) cache.Remove("UserByName_" + username.ToLowerInvariant()); } - - public void InvalidateItem(IUserDefinition user) - { - if (user is null) - return; - InvalidateById(user.Id); - InvalidateByUsername(user.Username); - } } \ No newline at end of file diff --git a/serene/src/Serene.Web/Modules/Membership/Account/SignUp/AccountPage.SignUp.cs b/serene/src/Serene.Web/Modules/Membership/Account/SignUp/AccountPage.SignUp.cs index 92d663d391..b96097b8d2 100644 --- a/serene/src/Serene.Web/Modules/Membership/Account/SignUp/AccountPage.SignUp.cs +++ b/serene/src/Serene.Web/Modules/Membership/Account/SignUp/AccountPage.SignUp.cs @@ -98,8 +98,7 @@ public Result SignUp(SignUpRequest request, uow.Commit(); - userRetriever.InvalidateById(userId.ToInvariant(), Cache); - userRetriever.InvalidateByUsername(username, Cache); + userRetriever.RemoveCachedUser(userId.ToInvariant(), username, Cache); if (environmentOptions?.Value.IsPublicDemo == true) { diff --git a/src/Serenity.Net.Core/Authorization/AuthorizationExtensions.cs b/src/Serenity.Net.Core/Authorization/AuthorizationExtensions.cs index c65665e705..0544c9cd76 100644 --- a/src/Serenity.Net.Core/Authorization/AuthorizationExtensions.cs +++ b/src/Serenity.Net.Core/Authorization/AuthorizationExtensions.cs @@ -135,20 +135,6 @@ public static void Impersonate(this IUserProvider userProvider, string username, userProvider.Impersonate(principal); } - /// - /// Tries to invalidate all users in cache if the user retrieve service implements IUserCacheInvalidator. - /// If not, it tries to expire all users in cache by group name "Default.Users" if cache is not null. - /// - /// User retrieve service - /// Optional cache - public static void InvalidateAll(this IUserRetrieveService userRetriever, ITwoLevelCache? cache) - { - if (userRetriever is IUserCacheInvalidator invalidator) - invalidator.InvalidateAll(); - else - cache?.ExpireGroupItems("Default.Users"); - } - /// /// Tries to invalidate user in cache if the user retrieve service implements IUserCacheInvalidator. /// If not, and cache is not null and user is not null, it tries to remove user by id and username from cache. @@ -156,44 +142,33 @@ public static void InvalidateAll(this IUserRetrieveService userRetriever, ITwoLe /// User retrieve service /// User /// Cache - public static void InvalidateItem(this IUserRetrieveService userRetriever, IUserDefinition? user, ITwoLevelCache? cache) + public static void RemoveCachedUser(this IUserRetrieveService userRetriever, IUserDefinition? user, ITwoLevelCache? cache) { - if (userRetriever is IUserCacheInvalidator invalidator) - invalidator.InvalidateItem(user); - else if (user != null) - { - userRetriever.InvalidateById(user.Id, cache); - userRetriever.InvalidateByUsername(user.Username, cache); - } + RemoveCachedUser(userRetriever, user?.Id, user?.Username, cache); } + /// - /// Tries to invalidate user by its id if the user retrieve service implements IUserCacheInvalidator. + /// Tries to invalidate user by its id / name if the user retrieve service implements IUserCacheInvalidator. /// If not, and cache is not null, it tries to remove user by id from cache. /// /// User retrieve service /// UserId + /// Username /// - public static void InvalidateById(this IUserRetrieveService userRetriever, string? userId, ITwoLevelCache? cache) + public static void RemoveCachedUser(this IUserRetrieveService userRetriever, string? userId, string? username, ITwoLevelCache? cache) { - if (userRetriever is IUserCacheInvalidator invalidator) - invalidator.InvalidateById(userId); - else if (userId != null) - cache?.Remove("UserByID_" + userId); - } + if (userRetriever is IRemoveCachedUser removeCachedUser) + { + removeCachedUser.RemoveCachedUser(userId, username); + return; + } - /// - /// Tries to invalidate user by its usernae if the user retrieve service implements IUserCacheInvalidator. - /// If not, and cache is not null, it tries to remove user by id from cache. - /// - /// User retrieve service - /// Username - /// Cache - public static void InvalidateByUsername(this IUserRetrieveService userRetriever, string? username, ITwoLevelCache? cache) - { - if (userRetriever is IUserCacheInvalidator invalidator) - invalidator.InvalidateByUsername(username); - else if (username != null) + if (userId != null) + cache?.Remove("UserById_" + userId); + + if (username != null) cache?.Remove("UserByName_" + username.ToLowerInvariant()); + } } \ No newline at end of file diff --git a/src/Serenity.Net.Core/Authorization/DefaultUserProvider.cs b/src/Serenity.Net.Core/Authorization/DefaultUserProvider.cs index f7adceef71..aaf5a4fb85 100644 --- a/src/Serenity.Net.Core/Authorization/DefaultUserProvider.cs +++ b/src/Serenity.Net.Core/Authorization/DefaultUserProvider.cs @@ -49,27 +49,18 @@ public void UndoImpersonate() } /// - public void InvalidateAll() + public void RemoveAll() { - userRetriever.InvalidateAll(cache); + if (userRetriever is IRemoveAll removeAll) + removeAll.RemoveAll(); + else + cache?.ExpireGroupItems("Default.Users"); } /// - public void InvalidateItem(IUserDefinition? user) + public void RemoveCachedUser(string? userId, string? username) { - userRetriever.InvalidateItem(user, cache); - } - - /// - public void InvalidateById(string? userId) - { - userRetriever.InvalidateById(userId, cache); - } - - /// - public void InvalidateByUsername(string? username) - { - userRetriever.InvalidateByUsername(username, cache); + userRetriever.RemoveCachedUser(userId, username, cache); } /// diff --git a/src/Serenity.Net.Core/Authorization/IRemoveCachedUser.cs b/src/Serenity.Net.Core/Authorization/IRemoveCachedUser.cs new file mode 100644 index 0000000000..272725694f --- /dev/null +++ b/src/Serenity.Net.Core/Authorization/IRemoveCachedUser.cs @@ -0,0 +1,13 @@ + +namespace Serenity.Abstractions; + +/// +/// Abstraction to remove a cached user by its id or username +/// +public interface IRemoveCachedUser +{ + /// + /// Removed cached user by its user ID and/or username + /// + void RemoveCachedUser(string? userId, string? username); +} diff --git a/src/Serenity.Net.Core/Authorization/IUserCacheInvalidator.cs b/src/Serenity.Net.Core/Authorization/IUserCacheInvalidator.cs deleted file mode 100644 index 61c82fa3f4..0000000000 --- a/src/Serenity.Net.Core/Authorization/IUserCacheInvalidator.cs +++ /dev/null @@ -1,28 +0,0 @@ - -namespace Serenity.Abstractions; - -/// -/// Abstraction to remove a cached user by its id or username -/// -public interface IUserCacheInvalidator -{ - /// - /// Removes all cached users - /// - void InvalidateAll(); - - /// - /// Invalidates cached user by its user definition - /// - void InvalidateItem(IUserDefinition? userDefinition); - - /// - /// Removes cached user by user ID - /// - void InvalidateById(string? userId); - - /// - /// Removes cached user by username - /// - void InvalidateByUsername(string? username); -} diff --git a/src/Serenity.Net.Core/Authorization/IUserProvider.cs b/src/Serenity.Net.Core/Authorization/IUserProvider.cs index a37ddbfcd7..ef4f8cb939 100644 --- a/src/Serenity.Net.Core/Authorization/IUserProvider.cs +++ b/src/Serenity.Net.Core/Authorization/IUserProvider.cs @@ -3,12 +3,9 @@ namespace Serenity.Abstractions; /// /// Abstraction that is a combination of IUserAccessor, IImpersonator, IUserClaimCreator, IUserRetrieveService and IUserCacheInvalidator. -/// Note that although it implements IImpersonator, its methods may throw exceptions if the underlying +/// Note that although the implements IImpersonator, its methods may throw exceptions if the underlying /// IUserAccessor does not implement IImpersonator. -/// It implements IUserCacheInvalidator but its methods may silently ignore or throw exceptions if the underlying IUserRetrieveService -/// does not implement IUserCacheInvalidator. The DefaultUserRetriever implementation does not throw exceptions in such cases and tries -/// to handle them gracefully. /// -public interface IUserProvider : IUserAccessor, IUserRetrieveService, IUserClaimCreator, IImpersonator, IUserCacheInvalidator +public interface IUserProvider : IUserAccessor, IUserRetrieveService, IUserClaimCreator, IImpersonator, IRemoveCachedUser, IRemoveAll { } \ No newline at end of file