为 ASP.NET 5 编写自定义身份验证类



箱即用 ASP.NET 5 个身份类很简单,易于设置和使用,但是我的问题是我正在使用具有现有用户和权限表的旧系统,我必须为其自定义身份系统。标识系统似乎非常可插拔,但我找不到有关如何编写自定义标识类的任何适当文档。是否有任何关于

  1. 如何编写自定义 ASP.NET 5 个可以满足旧系统用户和权限表的标识类
  2. 如何设置自定义标识类的使用以在 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>接口并实现了GetUserIdAsyncGetUserNameAsyncFindByIdAsyncGetClaimsAsync方法

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;

相关内容

  • 没有找到相关文章