Blazor Server脚手架身份认证无需EF Core对接Active Directory配置问题
问题原因
你遇到的报错本质是默认AddDefaultIdentity依赖IUserStore<IdentityUser>接口的实现,默认的EF Core存储实现由AddEntityFrameworkStores注入,你移除该方法后没有提供替代的存储实现,就会出现服务无法构造的错误。
你可以根据你的需求选择以下两种方案解决:
方案一:保留Identity SignInManager 用法,替换无数据库的自定义存储
如果你想继续使用脚手架生成的登录页原有逻辑,只需要自行实现一个轻量化的IUserStore<IdentityUser>,不需要对接数据库,仅实现登录必需的方法即可:
- 新增自定义用户存储类
public class CustomUserStore : IUserStore<IdentityUser> { // 实现登录必需的用户查询方法 public Task<IdentityUser> FindByIdAsync(string userId, CancellationToken cancellationToken) { return Task.FromResult(new IdentityUser(userId) { Id = userId }); } public Task<IdentityUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken) { return Task.FromResult(new IdentityUser(normalizedUserName.Normalize()) { Id = normalizedUserName, UserName = normalizedUserName }); } // 其余未用到的接口方法可以直接抛出未实现异常,运行时未调用就不会报错 public Task<string> GetUserIdAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.Id); public Task<string> GetUserNameAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.UserName); public Task SetUserNameAsync(IdentityUser user, string userName, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task<string> GetNormalizedUserNameAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.NormalizedUserName); public Task SetNormalizedUserNameAsync(IdentityUser user, string normalizedName, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task<IdentityResult> CreateAsync(IdentityUser user, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task<IdentityResult> UpdateAsync(IdentityUser user, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task<IdentityResult> DeleteAsync(IdentityUser user, CancellationToken cancellationToken) => throw new NotImplementedException(); public void Dispose() { } }
- 修改服务注册配置
将原来的Identity注册代码替换为以下内容,用自定义存储替换EF Core存储:
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false) .AddUserStore<CustomUserStore>();
修改完成后你原来写的_signInManager.SignInAsync逻辑就可以正常运行,不会再触发EF Core数据库连接。
方案二:绕过Identity存储依赖,直接使用Cookie认证
如果你不需要Identity的全套用户管理功能,仅需要AD校验后登录,更推荐直接使用原生Cookie认证,逻辑更简单,完全无EF Core依赖:
- 替换服务注册配置
删除原来的AddDefaultIdentity相关代码,改为注册Cookie认证服务:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Identity/Account/Login"; options.AccessDeniedPath = "/Identity/Account/AccessDenied"; // 可根据需求调整Cookie过期策略等配置 }); builder.Services.AddAuthorization(); // 注意Blazor Server还要保留app.UseAuthentication()、app.UseAuthorization()中间件配置
- 修改登录页逻辑
删掉Login.cshtml.cs中注入的SignInManager、UserManager,替换为自己的AD校验+Cookie登录逻辑:
public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl ??= Url.Content("~/"); if (ModelState.IsValid) { // 此处插入你自己的AD校验逻辑,校验用户名密码有效性 bool adValidationPassed = ValidateADAccount(Input.UserName, Input.Password); if (adValidationPassed) { // 构造用户声明,可根据AD返回的信息补充角色、邮箱等自定义声明 var claims = new List<Claim> { new Claim(ClaimTypes.Name, Input.UserName) }; var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); // 执行登录 await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties { IsPersistent = Input.RememberMe, ExpiresUtc = Input.RememberMe ? DateTimeOffset.UtcNow.AddDays(7) : null }); _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } ModelState.AddModelError(string.Empty, "用户名或密码错误"); } // 校验失败重新返回登录页 ExternalLogins = (await HttpContext.GetAuthenticationSchemesAsync()) .Where(x => x.DisplayName != null).ToList(); return Page(); }
内容的提问来源于stack exchange,提问作者d00d
相关产品推荐
相关产品推荐

