天天看点

.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置

参考文档:

1、https://docs.microsoft.com/zh-cn/aspnet/core/security/?view=aspnetcore-2.2

2、https://github.com/aspnet/AspNetCore.Docs/tree/live/aspnetcore/security/authentication/identity/sample/src

3、https://blog.csdn.net/sD7O95O/article/details/78623698
           

在Core2.2中,Identity的ORM默认使用了EF,但是这样,一些老项目迁移过程中就会遇到问题,因为很多项目还是使用的sql语句的方式访问数据库,这种情况下,显然不能重构项目为EF,不过,微软还是给Identity留下了自定义ORM的入口。

因为官方默认使用EF+sqlserver且使用了CodeFirst,所以下边的例子则为dapper+oracle,完全使用sql语句访问数据库,尽可能做到差异化。

一、数据库结构:

   因为是简单demo,所以配置一个简单的数据库,一个表,两个列足矣

    sys_user(userid varchar2,username varchar2,password varchar2)

二、新建一个core2.2项目:

.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置
.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置

测试一下,可以运行:

.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置

二、基础配置:

    1、appsettings.json配置文件中配置连接字符串“OracleConStr”:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "OracleConStr": "Data Source=****;Persist Security Info=True;User ID=**;Password=**;"
}
           

    2、使用NuGet安装所需类库:

1、Dapper
2、Oracle.ManagedDataAccess.Core
           

    3、创建SysUser实体类

public class SysUser : IIdentity
    {
        //必须实现的接口
        public string AuthenticationType { get; set; }
        public bool IsAuthenticated { get; set; }
        public string Name { get; set; }

        //根据表自定义的字段
        public string UserID { get; set; }
        public string UserName { get; set; }
        public string NormalizedUserName { get; set; }
        public string Password { get; set; }
        public string PasswordHash { get; set; }
    }
           

    4、创建表sysuser对应的Dal类SysUserDal,使用Dapper实现基本的增删改查

public class SysUserDal
    {
        private readonly OracleConnection _connection;
        public SysUserDal(OracleConnection connection)
        {
            _connection = connection;
        }

        public async Task<IdentityResult> CreateAsync(SysUser user)
        {
            string sql = "insert into sys_user (userid,username,password) values (:userid, :username,:password)";

            int rows = await _connection.ExecuteAsync(sql, new { userid = user.UserID, username = user.UserName, password = user.PasswordHash });

            if (rows > 0)
            {
                return IdentityResult.Success;
            }
            return IdentityResult.Failed(new IdentityError { Description = $"Could not insert user {user.UserID}." });
        }

        public async Task<IdentityResult> DeleteAsync(SysUser user)
        {
            string sql = "delete from sys_user where userid = :userid";
            int rows = await _connection.ExecuteAsync(sql, new { user.UserID });

            if (rows > 0)
            {
                return IdentityResult.Success;
            }
            return IdentityResult.Failed(new IdentityError { Description = $"Could not delete user {user.UserID}." });
        }

        public async Task<IdentityResult> UpdateAsync(SysUser user)
        {
            string sql = "update sys_user set password=:password,username=:username where userid=:userid";
            int rows = await _connection.ExecuteAsync(sql, new { userid = user.UserID, password = user.PasswordHash });
            if (rows > 0)
            {
                return IdentityResult.Success;
            }
            return IdentityResult.Failed(new IdentityError { Description = $"Could not update user {user.UserID}." });
        }

        public async Task<SysUser> FindByIdAsync(string userId)
        {
            string sql = "select * from sys_user where userid = :userid";

            return await _connection.QuerySingleOrDefaultAsync<SysUser>(sql, new
            {
                userid = userId
            });
        }
        public async Task<SysUser> FindByNameAsync(string userName)
        {
            string sql = "select * from sys_user where username = :username";

            return await _connection.QuerySingleOrDefaultAsync<SysUser>(sql, new
            {
                username = userName
            });
        }
    }
           

    4、创建SysuserRole

public class SysUserRole
    {
        public string UserID { get; set; } 
        public string UserName { get; set; } 
        public string Password { get; set; }
    }
           

    5、创建CustomUserStore

public class CustomUserStore : IUserStore<SysUser>, IUserPasswordStore<SysUser>
    {
        private readonly SysUserDal _usersTable;

        public CustomUserStore(SysUserDal usersTable)
        {
            _usersTable = usersTable;
        }

        #region createuser
        public async Task<IdentityResult> CreateAsync(SysUser user,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));

            return await _usersTable.CreateAsync(user);
        }
        #endregion

        public async Task<IdentityResult> DeleteAsync(SysUser user,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));

            return await _usersTable.DeleteAsync(user);

        }

        public void Dispose()
        {
        }

        public async Task<SysUser> FindByIdAsync(string userId,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (userId == null) throw new ArgumentNullException(nameof(userId));
            return await _usersTable.FindByIdAsync(userId);

        }

        public async Task<SysUser> FindByNameAsync(string userName,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (userName == null) throw new ArgumentNullException(nameof(userName));

            return await _usersTable.FindByNameAsync(userName);
        }

        public Task<string> GetNormalizedUserNameAsync(SysUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetPasswordHashAsync(SysUser user, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));

            return Task.FromResult(user.Password);
        }

        public Task<string> GetUserIdAsync(SysUser user, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));

            return Task.FromResult(user.UserID);
        }
        public Task<bool> CheckPasswordAsync(SysUser user, string pwd,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            return Task.FromResult(user.Password == pwd);
        }
        public Task<bool> IsEmailConfirmedAsync(SysUser user,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            return Task.FromResult(true);
        }

        public Task<string> GetUserNameAsync(SysUser user, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));

            return Task.FromResult(user.UserID);
        }

        public Task<bool> HasPasswordAsync(SysUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetNormalizedUserNameAsync(SysUser user, string normalizedName, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));
            if (normalizedName == null) throw new ArgumentNullException(nameof(normalizedName));

            user.NormalizedUserName = normalizedName;
            return Task.FromResult<object>(null);
        }

        public Task SetPasswordHashAsync(SysUser user, string passwordHash, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (user == null) throw new ArgumentNullException(nameof(user));
            if (passwordHash == null) throw new ArgumentNullException(nameof(passwordHash));

            user.PasswordHash = passwordHash;
            return Task.FromResult<object>(null);

        }

        public Task SetUserNameAsync(SysUser user, string userName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> UpdateAsync(SysUser user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
           

    6、创建CustomRoleStore

public class CustomRoleStore : IRoleStore<SysUserRole>
    {
        public Task<IdentityResult> CreateAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> DeleteAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
        }

        public Task<SysUserRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<SysUserRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetNormalizedRoleNameAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetRoleIdAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetRoleNameAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetNormalizedRoleNameAsync(SysUserRole role, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task SetRoleNameAsync(SysUserRole role, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public Task<IdentityResult> UpdateAsync(SysUserRole role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
           

    7、StartUp注入:ConfigureServices方法中添加

string connectionString = Configuration["OracleConStr"];
   services.AddTransient(e => new OracleConnection(connectionString));
   services.AddTransient<SysUserDal>();
   services.AddIdentity<SysUser, SysUserRole>().AddDefaultTokenProviders();
   services.AddTransient<IUserStore<SysUser>, CustomUserStore>();
   services.AddTransient<IRoleStore<SysUserRole>, CustomRoleStore>();
           

    8、StartUp中Configure的UseMVC之前添加

app.UseAuthentication();
           

    至此,基本的代码配置就完成了,下一步就是在controller中调用

三、controller+view使用Identity,因为是简单demo,所以代码比较简单,并不考虑实际使用场景

    1、创建AccountController

public class AccountController : Controller
    {
        private readonly UserManager<SysUser> _userManager;
        private readonly SignInManager<SysUser> _signInManager;
        public AccountController(UserManager<SysUser> userManager,
            SignInManager<SysUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }
        public IActionResult Index()
        {
            return View();
        }
        public async Task<IActionResult> Login()
        {
            string userid = "test";
            string pwd = "123ABCabc.";

            var result = await _signInManager.PasswordSignInAsync(userid, pwd, false, false);
            if (result.Succeeded)
            {
                //dosomething
            }
            else if (result.IsLockedOut)
            {
                //dosomething
            }
            else
            {
                ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            }
            return View();
        }
        public async Task<IActionResult> Register()
        {

            var user = new SysUser { UserID = "test", UserName = "测试" };
            var result = await _userManager.CreateAsync(user, "123ABCabc.");
            if (result.Succeeded)
            {
                //await _signInManager.SignInAsync(user, isPersistent: false);
            }
            else
            {
                //dosomething
            }
            return View();
        }
        public async Task<IActionResult> GetUser()
        {
            var res = await _userManager.GetUserAsync(HttpContext.User);
            return View();
        }
        public async Task<IActionResult> Logout()
        {
            await _signInManager.SignOutAsync();
            return View();
        }
    }
           

    2、创建每个Action的cshtml

    3、debug模式运行程序,在Account中的所有Action打断点,在SysUserDal所有方法打断点,使用浏览器地址栏调用Action,观察Identity工作流程,此处使用Register进行测试,不细看Debug过程,只看结果。

https://localhost:XXXXXX/Account/Register
           

观察数据库数据,发现数据已经被添加:

.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置

至此,可以证明Identity的ORM基础替换已经成功,此时的项目结构:

.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (一):基本配置

其他安全和权限类配置可根据使用场景阅读Microsoft Docs自定义开发