箱即用 ASP.NET 5 个身份类很简单,易于设置和使用,但是我的问题是我正在使用具有现有用户和权限表的旧系统,我必须为其自定义身份系统。标识系统似乎非常可插拔,但我找不到有关如何编写自定义标识类的任何适当文档。是否有任何关于
- 如何编写自定义 ASP.NET 5 个可以满足旧系统用户和权限表的标识类
- 如何设置自定义标识类的使用以在 ASP.NET 5、MVC 6 应用程序中使用?
目前还没有很多可用的文档,所以我尝试了当前Microsoft.AspNet.Identity.EntityFramework 3.0.0-rc1-final
的最新 Identity 类,并提出了一个适用于我的旧版用户数据库表的解决方案。
首先,确保您的旧用户实体类实现 IdentityUser
类,以便我们可以在 ASP.NET 5 内使用该类进行身份验证
public class MyLegacyUser : IdentityUser
{
// Your MyLegacyUser properties will go here as usual
}
确保忽略从不想使用的 IdentityUser
类继承的任何属性(这些属性未包含在用户表中)。我们通过在 DbContext
类的 OnModelCreating
方法中使用流畅的 api 来实现这一点。
public class MyDbContext : DbContext
{
public DbSet<MyLegacyUser> MyLegacyUser { get; set; }
// For simplicity I will add only the OnModelCreating method here
protected override void OnModelCreating
{
modelBuilder.Entity<MyLegacyUser>(entity =>
{
entity.Ignore(e => e.AccessFailedCount);
entity.Ignore(e => e.Claims);
entity.Ignore(e => e.ConcurrencyStamp);
entity.Ignore(e => e.Email);
entity.Ignore(e => e.EmailConfirmed);
entity.Ignore(e => e.Id);
entity.Ignore(e => e.LockoutEnabled);
entity.Ignore(e => e.LockoutEnd);
entity.Ignore(e => e.Logins);
entity.Ignore(e => e.NormalizedEmail);
entity.Ignore(e => e.NormalizedUserName);
entity.Ignore(e => e.PasswordHash);
entity.Ignore(e => e.PhoneNumber);
entity.Ignore(e => e.PhoneNumberConfirmed);
entity.Ignore(e => e.Roles);
entity.Ignore(e => e.SecurityStamp);
entity.Ignore(e => e.TwoFactorEnabled);
}
}
}
现在,我们必须实现自己的自定义UserManager
类,以向旧用户进行身份验证。确保你的新类实现了UserManager<T>
,其中T
是你的MyLegacyUser
。完成此操作后,覆盖CheckPasswordAsync
以对用户进行身份验证。
注意:CheckPasswordAsync
方法不负责返回经过身份验证的用户,它只是一个将返回 true 或 false 以指示用户是否已成功进行身份验证的方法。经过身份验证的用户由另一个类设置,我将在下面解释。
public class MyLegacyUserManager : UserManager<MyLegacyUser>
{
public WorldUserManager(IUserStore<MasterUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<MasterUser> passwordHasher, IEnumerable<IUserValidator<MasterUser>> userValidators, IEnumerable<IPasswordValidator<MasterUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<MasterUser>> logger, IHttpContextAccessor contextAccessor) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, contextAccessor)
{
}
public override async Task<bool> CheckPasswordAsync(MasterUser user, string password)
{
// This is my own authentication manager class that handles user authentication
// Add your own code to authenticate your user here
return new AuthenticationManager().Authenticate(user.EmailAddress, password);
}
}
完成此操作后,我们必须实现自己的UserStore
类。您可以实现一些接口,例如IUserStore<T>
、IUserLoginStore<T>
、IUserClaimsStore<T>
等。我实现了IUserClaimsStore<T>
接口并实现了GetUserIdAsync
、GetUserNameAsync
、FindByIdAsync
和GetClaimsAsync
方法
public class MyLegacyUserClaimStore : IUserClaimStore<MyLegacyUser>
{
// Here I simply returned the username of the user parameter I recieved as input
public Task<string> GetUserIdAsync(MasterUser user, CancellationToken cancellationToken)
{
return Task.Run(() => user.UserName, cancellationToken);
}
}
// Here I simply returned the username of the user parameter I recieved as input
public Task<string> GetUserNameAsync(MasterUser user, CancellationToken cancellationToken)
{
return Task.Run(() => user.UserName, cancellationToken);
}
public Task<MasterUser> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
// This is my manager class to read my user for the userId
// Add your own code to read the user for the set Id here
return Task.Run(() => new MyLegacyUserUserManager().ReadForEmailAddress(userId, 0, true, true), cancellationToken);
}
public Task<MasterUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
// This is my manager class to read my user for the normalizedUserName
// Add your own code to read the user for the set normalizedUserName here
return Task.Run(() => new MyLegacyUserManager().ReadForEmailAddress(normalizedUserName, 0, true, true), cancellationToken);
}
// If you want to make use of Claims make sure that you map them here
// If you do not use claims, consider implementing one of the other IUserStore interfaces
//such as the IUserLoginStore so that you do not have to implement the GetClaimsAsync method
public async Task<IList<Claim>> GetClaimsAsync(MasterUser user, CancellationToken cancellationToken)
{
var claims = new List<Claim>();
foreach (var claim in user.Claims)
{
claims.Add(new Claim(claim.ClaimType, claim.ClaimValue));
}
return claims;
}
这些是自定义身份验证所需的所有类。不,让我们在 Startup.cs
类中配置自定义身份验证方法。将以下内容添加到ConfigureServices
方法
public void ConfigureServices(IServiceCollection services)
{
// Use the default role, IdentityRole as we are not implementing roles
// Add our custom UserManager and UserStore classes
services.AddIdentity<MyLegacyUser, IdentityRole>(config =>
{
config.User.RequireUniqueEmail = true;
config.Cookies.ApplicationCookie.AccessDeniedPath = new Microsoft.AspNet.Http.PathString("/Auth/Login");
config.Cookies.ApplicationCookie.LoginPath = new Microsoft.AspNet.Http.PathString("/Auth/Login");
config.Cookies.ApplicationCookie.LogoutPath = new Microsoft.AspNet.Http.PathString("/Auth/Login");
})
.AddUserManager<MyLegacyUserManager>()
.AddUserStore<MyLegacyUserUserClaimStore>()
.AddEntityFrameworkStores<MyDbContext>();
}
在 Configure
方法中,请确保指定要使用标识功能进行身份验证
注意:use 语句的顺序很重要,如果您使用的是 Mvc,请确保在UseMvc
之前包含UseIdentity
。
public async void Configure(IApplicationBuilder app)
{
app.UseIdentity();
// Your useMvc and other use statements will go here
}
现在,我们已经配置了自定义身份验证类,可以使用默认SignInManager
类进行身份验证。这是我的AuthController
课的例子
public class AuthController : Controller
{
private SignInManager<MyLegacyUserUser> _signInManager;
public AuthController(SignInManager<MasterUser> signInManager)
{
_signInManager = signInManager;
}
// For simplicity I will only add the Login action here
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel loginViewModel)
{
var result = await _signInManager.PasswordSignInAsync(loginViewModel.Username, loginViewModel.Password, true, false);
if (result == SignInResult.Success)
{
return RedirectToAction("Index", "SomeControllerToRedirectTo");
}
await _signInManager.SignOutAsync();
return RedirectToAction("Login", "Auth");
}
}
当您的用户通过身份验证时,您可以像使用 MVC 5 一样访问用户声明,例如
var email = User.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.Email)).Value;