编写自定义的验证类ASP.NET 5 [英] Write Custom Authentication classes for ASP.NET 5

查看:147
本文介绍了编写自定义的验证类ASP.NET 5的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

的开箱即用ASP.NET 5身份类是直线前进,这是易于安装和使用,但我的问题是,我与我有自定义现有的用户和权限表的遗留系统工作为识别系统。该识别系统似乎很可插拔的,但我不能找到如何编写自定义身份类的任何适当的文件。是否有

任何文件

  1. 如何编写自定义的,可容纳遗留系统的用户和权限表ASP.NET 5标识类

  2. 如何设置使用自定义标识类用在ASP.NET 5,6 MVC应用程序?


解决方案

有没有大量的文档资料可用,所以我用最新的身份类这是目前发挥各地 Microsoft.AspNet.Identity .EntityFramework 3.0.0-RC1决赛,并想出了正与我的遗产用户数据库表的解决方案。

首先确保您的旧用户实体类实现 IdentityUser 类,使我们可以ASP.NET 5

中使用的类认证

 公共类MyLegacyUser:IdentityUser
{
    //你MyLegacyUser属性将去这里像往常一样
}

请确保您忽略,你会不喜欢使用 IdentityUser 类继承的任何属性(这些都是不包含用户表中的属性)。我们通过使用中的流畅API实现的 OnModelCreating 的DbContext 类的方法。

 公共类MyDbContext:的DbContext
{
    公共DbSet< MyLegacyUser> MyLegacyUser {搞定;组; }    //为简单起见,我将在这里只添加OnModelCreating方法
    保护覆盖无效OnModelCreating
    {
        modelBuilder.Entity< MyLegacyUser>(实体=>
        {
            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指示的方法如果用户被成功认证。通过身份验证的用户被其他类设置,我下面会解释。

 公共类MyLegacyUserManager:&的UserManager LT; MyLegacyUser>
{
    公共WorldUserManager(IUserStore< MasterUser>商店,IOptions< IdentityOptions> optionsAccessor,IPasswordHasher< MasterUser> passwordHasher,IEnumerable的< IUserValidator< MasterUser>> userValidators,IEnumerable的< IPasswordValidator< MasterUser>> passwordValidators,ILookupNormalizer keyNormalizer,IdentityErrorDescriber错误,IServiceProvider的服务, ILogger<&的UserManager LT; MasterUser>>记录仪,IHttpContextAccessor ​​contextAccessor):基地(商店,optionsAccessor,passwordHasher,userValidators,passwordValidators,keyNormalizer,错误,服务,记录仪,contextAccessor)
    {
    }    公共覆盖异步任务<布尔> CheckPasswordAsync(MasterUser用户,字符串密码)
    {
        //这是处理用户身份验证自己的身份验证管理器类
       //添加您自己的code在这里验证您的用户
        返回新的AuthenticationManager()进行身份验证(user.EmailAddress,密码)。
    }
}

一旦做到这一点,我们必须实现我们自己的 UserStore 类。还有可以实现几个接口,如 IUserStore< T> IUserLoginStore< T> IUserClaimsStore< T> 等我实现了 IUserClaimsStore< T> 接口和实施 GetUserIdAsync GetUserNameAsync FindByIdAsync GetClaimsAsync 方法

 公共类MyLegacyUserClaimStore:IUserClaimStore< MyLegacyUser>
{
    //我在这里简单地回到我收到的用户输入参数的用户名
    公共任务<串GT; GetUserIdAsync(MasterUser用户的CancellationToken的CancellationToken)
    {
        返回Task.Run(()=> user.UserName,的CancellationToken);
    }
}//我在这里简单地回到我收到的用户输入参数的用户名
公共任务<串GT; GetUserNameAsync(MasterUser用户的CancellationToken的CancellationToken)
{
    返回Task.Run(()=> user.UserName,的CancellationToken);
}公共任务< MasterUser> FindByIdAsync(字符串userid,的CancellationToken的CancellationToken)
{
    //这是我的经理类读取我的用户的用户id
    //添加您自己的code读到这里为集ID用户
    返回Task.Run(()=>新建MyLegacyUserUserManager()ReadForEmailAddress(用户ID,0,真实,真)的CancellationToken);
} 公共任务< MasterUser> FindByNameAsync(字符串normalizedUserName,的CancellationToken的CancellationToken)
 {
     //这是我的经理类读取我的用户为normalizedUserName
    //添加您自己的code读到这里的一套normalizedUserName用户
     返回Task.Run(()=>新建MyLegacyUserManager()ReadForEmailAddress(normalizedUserName,0,真实,真)的CancellationToken);
 }//如果你想利用索赔确保你在这里将它们映射
//如果你不使用要求,需要考虑其他的IUserStore接口之一
//如IUserLoginStore,这样你就不必执行GetClaimsAsync方法
公共异步任务<&IList的LT;权利要求GT;> GetClaimsAsync(MasterUser用户的CancellationToken的CancellationToken)
{
    VAR索赔=新的List<权利要求GT;();    的foreach(VAR索赔user.Claims)
    {
        claims.Add(新索赔(claim.ClaimType,claim.ClaimValue));
    }    返回索赔;
}

这些都是你需要进行自定义验证的类。没有让我们配置我们在 Startup.cs自定义的验证方法类。添加以下到 ConfigureServices

 公共无效ConfigureServices(IServiceCollection服务)
{
     //使用默认的角色,IdentityRole因为我们没有实现角色
     //添加我们的自定义的UserManager和UserStore类
     services.AddIdentity< MyLegacyUser,IdentityRole&GT(配置=>
        {
            config.User.RequireUniqueEmail = TRUE;
            config.Cookies.ApplicationCookie.AccessDeniedPath =新Microsoft.AspNet.Http.PathString(/认证/登录);
            config.Cookies.ApplicationCookie.LoginPath =新Microsoft.AspNet.Http.PathString(/认证/登录);
            config.Cookies.ApplicationCookie.LogoutPath =新Microsoft.AspNet.Http.PathString(/认证/登录);
        })
        .AddUserManager< MyLegacyUserManager>()
        .AddUserStore< MyLegacyUserUserClaimStore>()
        .AddEntityFrameworkStores< MyDbContext>();
}

配置方法确保您指定要使用的功能,身份验证

注意:您使用的语句的顺序很重要,请确保您包括 UseIdentity UseMvc 如果你正在使用MVC。

 公共异步无效配置(IApplicationBuilder应用程序)
{
    app.UseIdentity();
    //你useMvc等使用的语句会去这里
}

现在我们已经配置了自定义验证类,我们可以使用默认的 SignInManager 类认证。下面是一个例子我 AuthController

 公共类AuthController:控制器
{
    私人SignInManager< MyLegacyUserUser> _signInManager;    公共AuthController(SignInManager< MasterUser> signInManager)
    {
        _signInManager = signInManager;
    }    //为简单起见,我将只在这里添加登录动作
    [HttpPost]
    公共异步任务< IActionResult>登录(LoginViewModel loginViewModel)
    {
        VAR的结果=等待_signInManager.PasswordSignInAsync(loginViewModel.Username,loginViewModel.Password,真,假);        如果(结果== SignInResult.Success)
        {
            返回RedirectToAction(指数,SomeControllerToRedirectTo);
        }        等待_signInManager.SignOutAsync();        返回RedirectToAction(登录,验证);
    }
}

当你的用户进行身份验证就可以访问该用户的权利要求你会使用MVC 5完成的,例如:

  VAR电子邮件= User.Claims.FirstOrDefault(C => c.Type.Equals(ClaimTypes.Email))值。

The out of the box ASP.NET 5 Identity classes are straight forward and it is easy to setup and use, my problem however is that I'm working with a legacy system with existing user and permission tables that I have to customize the Identity system for. The Identity system seems very pluggable, but I can't find any proper documentation on how to write custom Identity classes. Is there any documentation on

  1. How to write custom ASP.NET 5 Identity classes that can cater for legacy system user and permission tables
  2. How do I setup the use of the custom Identity classes for use in a ASP.NET 5, MVC 6 application?

解决方案

There is not a lot of documentation available yet, so I played around with the latest Identity classes which is currently Microsoft.AspNet.Identity.EntityFramework 3.0.0-rc1-final and came up with a solution that is working with my legacy user database tables.

First of all make sure that your legacy user entity class implement the IdentityUser class so that we can use the class for authentication within ASP.NET 5

public class MyLegacyUser : IdentityUser
{
    // Your MyLegacyUser properties will go here as usual
}

Make sure that you ignore any properties inherited from the IdentityUser class that you would not like to use (Those are the properties not contained within your user table). We do this by using the fluent api within the OnModelCreating method of the DbContext class.

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);
        }
    }
}

Now we have to implement our own custom UserManager class to authenticate with our legacy user. Make sure that your new class implement UserManager<T>, where T is your MyLegacyUser. Once this is done override the CheckPasswordAsync to authenticate your user.

Note: The CheckPasswordAsync method is not responsible for returning an authenticated user, it is simply a method that will return true or false to indicate if the user was successfully authenticated. The authenticated user is set by another class which I will explain below.

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);
    }
}    

Once this is done we have to implement our own UserStore class. There are a few interfaces you can implement such as IUserStore<T>, IUserLoginStore<T>, IUserClaimsStore<T> etc. I implemented the IUserClaimsStore<T> interface and implemented the GetUserIdAsync, GetUserNameAsync, FindByIdAsync and GetClaimsAsync methods

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;
}

These are all the classes you need for custom authentication. No let's configure our custom authentication method in the Startup.cs class. Add the following to the ConfigureServices method

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>();
} 

In the Configure method make sure that you specify that you want to use the Identity functionality to authenticate

Note: The order of your use statements are important, make sure that you include UseIdentity before UseMvc if you are using Mvc.

public async void Configure(IApplicationBuilder app)
{
    app.UseIdentity();
    // Your useMvc and other use statements will go here
}

Now we have configured our custom authentication classes and we can authenticate by using the default SignInManager class. Here is an example of my AuthController class

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");
    }
}

When your user is authenticated you can access the user claims as you would have done with MVC 5, for example

var email = User.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.Email)).Value;

这篇关于编写自定义的验证类ASP.NET 5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆