问题
this is a follow-up question to the one posted here earlier today InvalidCastException on an LDAP implementation in ASP Boilerplate as suggested by just.another.programmer
I seem to be running into another issue this time having no component supported as described here in the logs
The code from before
LdapAuthentication.cs:
public abstract class LdapAuthenticationSource<TTenant, TUser> : DefaultExternalAuthenticationSource<TTenant, TUser>, ITransientDependency
where TTenant : AbpTenant<TUser>
where TUser : AbpUserBase, new()
{
/// <summary>
/// LDAP
/// </summary>
public const string SourceName = "LDAP";
public override string Name
{
get { return SourceName; }
}
private readonly ILdapSettings _settings;
private readonly IAbpZeroLdapModuleConfig _ldapModuleConfig;
protected LdapAuthenticationSource(ILdapSettings settings, IAbpZeroLdapModuleConfig ldapModuleConfig)
{
_settings = settings;
_ldapModuleConfig = ldapModuleConfig;
}
/// <inheritdoc/>
public override async Task<bool> TryAuthenticateAsync(string userNameOrEmailAddress, string plainPassword, TTenant tenant)
{
if (!_ldapModuleConfig.IsEnabled || !(await _settings.GetIsEnabled(GetIdOrNull(tenant))))
{
return false;
}
using (var principalContext = await CreatePrincipalContext(tenant))
{
return ValidateCredentials(principalContext, userNameOrEmailAddress, plainPassword);
}
}
/// <inheritdoc/>
public async override Task<TUser> CreateUserAsync(string userNameOrEmailAddress, TTenant tenant)
{
await CheckIsEnabled(tenant);
var user = await base.CreateUserAsync(userNameOrEmailAddress, tenant);
using (var principalContext = await CreatePrincipalContext(tenant))
{
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, userNameOrEmailAddress);
if (userPrincipal == null)
{
throw new AbpException("Unknown LDAP user: " + userNameOrEmailAddress);
}
UpdateUserFromPrincipal(user, userPrincipal);
user.IsEmailConfirmed = true;
user.IsActive = true;
return user;
}
}
public async override Task UpdateUserAsync(TUser user, TTenant tenant)
{
await CheckIsEnabled(tenant);
await base.UpdateUserAsync(user, tenant);
using (var principalContext = await CreatePrincipalContext(tenant))
{
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, user.UserName);
if (userPrincipal == null)
{
throw new AbpException("Unknown LDAP user: " + user.UserName);
}
UpdateUserFromPrincipal(user, userPrincipal);
}
}
protected virtual bool ValidateCredentials(PrincipalContext principalContext, string userNameOrEmailAddress, string plainPassword)
{
return principalContext.ValidateCredentials(userNameOrEmailAddress, plainPassword, ContextOptions.Negotiate);
}
protected virtual void UpdateUserFromPrincipal(TUser user, UserPrincipal userPrincipal)
{
user.UserName = userPrincipal.SamAccountName;
user.Name = userPrincipal.GivenName;
user.Surname = userPrincipal.Surname;
user.EmailAddress = userPrincipal.EmailAddress;
if (userPrincipal.Enabled.HasValue)
{
user.IsActive = userPrincipal.Enabled.Value;
}
}
protected virtual async Task<PrincipalContext> CreatePrincipalContext(TTenant tenant)
{
var tenantId = GetIdOrNull(tenant);
return new PrincipalContext(
await _settings.GetContextType(tenantId),
ConvertToNullIfEmpty(await _settings.GetDomain(tenantId)),
ConvertToNullIfEmpty(await _settings.GetContainer(tenantId)),
ConvertToNullIfEmpty(await _settings.GetUserName(tenantId)),
ConvertToNullIfEmpty(await _settings.GetPassword(tenantId))
);
}
private async Task CheckIsEnabled(TTenant tenant)
{
if (!_ldapModuleConfig.IsEnabled)
{
throw new AbpException("Ldap Authentication module is disabled globally!");
}
var tenantId = GetIdOrNull(tenant);
if (!await _settings.GetIsEnabled(tenantId))
{
throw new AbpException("Ldap Authentication is disabled for given tenant (id:" + tenantId + ")! You can enable it by setting '" + LdapSettingNames.IsEnabled + "' to true");
}
}
private static int? GetIdOrNull(TTenant tenant)
{
return tenant == null
? (int?)null
: tenant.Id;
}
private static string ConvertToNullIfEmpty(string str)
{
return str.IsNullOrWhiteSpace()
? null
: str;
}
}
}
LdapSettings.cs
public class LdapSettings: ILdapSettings, ITransientDependency
{
protected ISettingManager SettingManager { get; }
public LdapSettings(ISettingManager settingManager)
{
SettingManager = settingManager;
}
public virtual Task<bool> GetIsEnabled(int? tenantId)
{
return tenantId.HasValue
? SettingManager.GetSettingValueForTenantAsync<bool>(AppSettingNames.IsEnabled, tenantId.Value)
: SettingManager.GetSettingValueForApplicationAsync<bool>(AppSettingNames.IsEnabled);
}
public virtual async Task<ContextType> GetContextType(int? tenantId)
{
return tenantId.HasValue
? (await SettingManager.GetSettingValueForTenantAsync(AppSettingNames.ContextType, tenantId.Value)).ToEnum<ContextType>()
: (await SettingManager.GetSettingValueForApplicationAsync(AppSettingNames.ContextType)).ToEnum<ContextType>();
}
public virtual Task<string> GetContainer(int? tenantId)
{
return tenantId.HasValue
? SettingManager.GetSettingValueForTenantAsync(AppSettingNames.Container, tenantId.Value)
: SettingManager.GetSettingValueForApplicationAsync(AppSettingNames.Container);
}
public virtual Task<string> GetDomain(int? tenantId)
{
return tenantId.HasValue
? SettingManager.GetSettingValueForTenantAsync(AppSettingNames.Domain, tenantId.Value)
: SettingManager.GetSettingValueForApplicationAsync(AppSettingNames.Domain);
}
public virtual Task<string> GetUserName(int? tenantId)
{
return tenantId.HasValue
? SettingManager.GetSettingValueForTenantAsync(AppSettingNames.UserName, tenantId.Value)
: SettingManager.GetSettingValueForApplicationAsync(AppSettingNames.UserName);
}
public virtual Task<string> GetPassword(int? tenantId)
{
return tenantId.HasValue
? SettingManager.GetSettingValueForTenantAsync(AppSettingNames.Password, tenantId.Value)
: SettingManager.GetSettingValueForApplicationAsync(AppSettingNames.Password);
}
}
}
CoreModule.cs
[DependsOn(typeof(AbpZeroLdapModule))]
public class TestApp2020CoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Auditing.IsEnabledForAnonymousUsers = true;
// Declare entity types
Configuration.Modules.Zero().EntityTypes.Tenant = typeof(Tenant);
Configuration.Modules.Zero().EntityTypes.Role = typeof(Role);
Configuration.Modules.Zero().EntityTypes.User = typeof(User);
TestApp2020LocalizationConfigurer.Configure(Configuration.Localization);
// Enable this line to create a multi-tenant application.
Configuration.MultiTenancy.IsEnabled = TestApp2020Consts.MultiTenancyEnabled;
// IocManager.Register<ILdapSettings, MyLdapSettings>(); //change default setting source
IocManager.Register<ILdapSettings, LdapSettings>();
Configuration.Modules.ZeroLdap().Enable(typeof(LdapSettings));
// Configure roles
AppRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
Configuration.Settings.Providers.Add<AppSettingProvider>();
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(TestApp2020CoreModule).GetAssembly());
}
public override void PostInitialize()
{
IocManager.Resolve<AppTimes>().StartupTime = Clock.Now;
SettingManager settingsManager = IocManager.Resolve<SettingManager>();
settingsManager.ChangeSettingForApplication(AppSettingNames.IsEnabled, "true");
}
}
}
Once again, all help will be appreciated, thanks
回答1:
The problem is almost certainly with the constructor you used for LdapAuthenticationSource
. There's two problems
- You declared the constructor
protected
. That means the IoC framework isn't able to create a newLdapAuthenticationSource
. - You didn't call the
base
constructor from your inherited class. Instead, you stored the params in fields of the derived class so the base class cannot access them!
Try changing the constructor like this
public LdapAuthenticationSource(ILdapSettings settings, IAbpZeroLdapModuleConfig ldapModuleConfig) : base(settings, ldapModuleConfig) { }
and removing these two lines
private readonly ILdapSettings _settings;
private readonly IAbpZeroLdapModuleConfig _ldapModuleConfig;
来源:https://stackoverflow.com/questions/62191897/mvc-exceptionhandling-abpexceptionfilter-no-component-found