diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs
index 0f41cdce..b0f558e6 100644
--- a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs
+++ b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs
@@ -8,7 +8,7 @@ namespace Masa.Auth.Contracts.Admin.Infrastructure.Password;
/// A client-level rule (stored on ClientConfig) takes precedence; when absent it falls back to
/// the global DCC configuration.
///
-public interface IPasswordRuleProvider
+public interface IPasswordRuleProvider : IScopedDependency
{
///
/// Validate a password against the client's effective rule.
@@ -16,6 +16,8 @@ public interface IPasswordRuleProvider
/// Designed to be called from a FluentValidation rule (see )
/// so client-aware password validation stays inside the single, framework-invoked validation pipeline.
///
+ string? GetFailure(string? password, string? clientId);
+
Task GetFailureAsync(string? password, string? clientId);
///
diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs
index e3da97f2..1a36430e 100644
--- a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs
+++ b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs
@@ -15,9 +15,9 @@ public static class PasswordRuleValidatorExtensions
IPasswordRuleProvider passwordRuleProvider,
Func clientId)
{
- return ruleBuilder.CustomAsync(async (password, context, cancellation) =>
+ return ruleBuilder.Custom((password, context) =>
{
- var failure = await passwordRuleProvider.GetFailureAsync(password, clientId(context.InstanceToValidate));
+ var failure = passwordRuleProvider.GetFailure(password, clientId(context.InstanceToValidate));
if (failure is not null)
{
context.AddFailure(failure);
diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs
index 2a6163f3..f9c9beb6 100644
--- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs
@@ -16,8 +16,6 @@ public ResetPasswordCommandValidator(PhoneNumberValidator phoneValidator, IPassw
RuleFor(x => x.Voucher).Required().Email();
});
RuleFor(x => x.Captcha).Required();
- // Anonymous forgot-password flow (no login) - the client rule follows whatever ClientId
- // the caller passes for this request; falls back to the global DCC rule when absent.
RuleFor(x => x.Password).PasswordRule(passwordRuleProvider, x => x.ClientId);
RuleFor(x => x.ConfirmPassword).Equal(x => x.Password);
}
diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs
index 6f27dc5b..1cb22f8f 100644
--- a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs
@@ -3,7 +3,7 @@
namespace Masa.Auth.Service.Admin.Infrastructure.Message;
-public class ClientMessageTemplateProvider : IClientMessageTemplateProvider, IScopedDependency
+public class ClientMessageTemplateProvider : IClientMessageTemplateProvider
{
private readonly IClientConfigRepository _clientConfigRepository;
diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs
index f461dcd8..807a3647 100644
--- a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs
@@ -8,7 +8,7 @@ namespace Masa.Auth.Service.Admin.Infrastructure.Message;
/// (channel type, scene). Returns null when the client has no matching configuration,
/// signalling the caller to fall back to the global DCC SmsOptions/EmailOptions.
///
-public interface IClientMessageTemplateProvider
+public interface IClientMessageTemplateProvider : IScopedDependency
{
Task<(string channelCode, string templateCode)?> ResolveAsync(string? clientId, ChannelTypes channelType, int scene);
}
diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs
index dc4a372a..b3e21c64 100644
--- a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs
@@ -5,7 +5,7 @@
namespace Masa.Auth.Service.Admin.Infrastructure.Password;
-public class PasswordRuleProvider : IPasswordRuleProvider, IScopedDependency
+public class PasswordRuleProvider : IPasswordRuleProvider
{
public const string PASSWORDRULECONFIGNAME = "$public.AppSettings:PasswordRule";
public const string PASSWORDPROMPTCONFIGNAME = "$public.AppSettings:PasswordPrompt";
@@ -26,6 +26,12 @@ public PasswordRuleProvider(
_logger = logger;
}
+ public string? GetFailure(string? password, string? clientId)
+ {
+ var (rule, prompt) = GetEffectiveRule(clientId);
+ return ValidatePasswordWithRule(password, rule, prompt);
+ }
+
public async Task GetFailureAsync(string? password, string? clientId)
{
var (rule, prompt) = await GetEffectiveRuleAsync(clientId);
@@ -38,6 +44,26 @@ public Task GenerateNewPasswordAsync()
return Task.FromResult(GenerateNewPassword(passwordRule));
}
+ private (string rule, string prompt) GetEffectiveRule(string? clientId)
+ {
+ var (rule, prompt) = GetGlobalPasswordRule();
+
+ if (!string.IsNullOrEmpty(clientId))
+ {
+ var clientConfig = _clientConfigRepository.FindByClientIdAsync(clientId).Result;
+ if (clientConfig is not null && !string.IsNullOrEmpty(clientConfig.PasswordRule))
+ {
+ rule = clientConfig.PasswordRule;
+ if (!string.IsNullOrEmpty(clientConfig.PasswordPrompt))
+ {
+ prompt = clientConfig.PasswordPrompt;
+ }
+ }
+ }
+
+ return (rule, prompt);
+ }
+
private async Task<(string rule, string prompt)> GetEffectiveRuleAsync(string? clientId)
{
// 全局 DCC 配置作为回退默认值
diff --git a/src/Services/Masa.Auth.Service.Admin/Program.cs b/src/Services/Masa.Auth.Service.Admin/Program.cs
index bc0e95a6..64256bb1 100644
--- a/src/Services/Masa.Auth.Service.Admin/Program.cs
+++ b/src/Services/Masa.Auth.Service.Admin/Program.cs
@@ -18,7 +18,6 @@
#endif
builder.Services.AddAutoInject();
-builder.Services.AddScoped();
builder.Services.AddDaprClient();
builder.Services.AddObjectStorage(option => option.UseAliyunStorage());
diff --git a/src/Services/Masa.Auth.Service.Admin/_Imports.cs b/src/Services/Masa.Auth.Service.Admin/_Imports.cs
index 072b1ac4..9f0b92f6 100644
--- a/src/Services/Masa.Auth.Service.Admin/_Imports.cs
+++ b/src/Services/Masa.Auth.Service.Admin/_Imports.cs
@@ -85,6 +85,7 @@
global using Masa.Auth.Service.Admin.Infrastructure.Message;
global using Masa.Auth.Service.Admin.Infrastructure.Middleware;
global using Masa.Auth.Service.Admin.Infrastructure.Models;
+global using Masa.Auth.Service.Admin.Infrastructure.Password;
global using Masa.Auth.Service.Admin.Infrastructure.Sms;
global using Masa.Auth.Service.Admin.Infrastructure.Utils;
global using Masa.BuildingBlocks.Authentication.Identity;