参考文档:
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项目:
测试一下,可以运行:
二、基础配置:
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 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 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 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 FindByIdAsync(string userId)
{
string sql = "select * from sys_user where userid = :userid";
return await _connection.QuerySingleOrDefaultAsync(sql, new
{
userid = userId
});
}
public async Task FindByNameAsync(string userName)
{
string sql = "select * from sys_user where username = :username";
return await _connection.QuerySingleOrDefaultAsync(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, IUserPasswordStore
{
private readonly SysUserDal _usersTable;
public CustomUserStore(SysUserDal usersTable)
{
_usersTable = usersTable;
}
#region createuser
public async Task 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 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 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 FindByNameAsync(string userName,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
if (userName == null) throw new ArgumentNullException(nameof(userName));
return await _usersTable.FindByNameAsync(userName);
}
public Task GetNormalizedUserNameAsync(SysUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task GetPasswordHashAsync(SysUser user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null) throw new ArgumentNullException(nameof(user));
return Task.FromResult(user.Password);
}
public Task GetUserIdAsync(SysUser user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null) throw new ArgumentNullException(nameof(user));
return Task.FromResult(user.UserID);
}
public Task CheckPasswordAsync(SysUser user, string pwd,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(user.Password == pwd);
}
public Task IsEmailConfirmedAsync(SysUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(true);
}
public Task GetUserNameAsync(SysUser user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null) throw new ArgumentNullException(nameof(user));
return Task.FromResult(user.UserID);
}
public Task 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
6、创建CustomRoleStore
public class CustomRoleStore : IRoleStore
{
public Task CreateAsync(SysUserRole role, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task DeleteAsync(SysUserRole role, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
}
public Task FindByIdAsync(string roleId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task GetNormalizedRoleNameAsync(SysUserRole role, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task GetRoleIdAsync(SysUserRole role, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task 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 UpdateAsync(SysUserRole role, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
7、StartUp注入:ConfigureServices方法中添加
string connectionString = Configuration["OracleConStr"];
services.AddTransient(e => new OracleConnection(connectionString));
services.AddTransient();
services.AddIdentity().AddDefaultTokenProviders();
services.AddTransient, CustomUserStore>();
services.AddTransient, CustomRoleStore>();
8、StartUp中Configure的UseMVC之前添加
app.UseAuthentication();
至此,基本的代码配置就完成了,下一步就是在controller中调用
三、controller+view使用Identity,因为是简单demo,所以代码比较简单,并不考虑实际使用场景
1、创建AccountController
public class AccountController : Controller
{
private readonly UserManager _userManager;
private readonly SignInManager _signInManager;
public AccountController(UserManager userManager,
SignInManager signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public IActionResult Index()
{
return View();
}
public async Task 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 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 GetUser()
{
var res = await _userManager.GetUserAsync(HttpContext.User);
return View();
}
public async Task Logout()
{
await _signInManager.SignOutAsync();
return View();
}
}
2、创建每个Action的cshtml
3、debug模式运行程序,在Account中的所有Action打断点,在SysUserDal所有方法打断点,使用浏览器地址栏调用Action,观察Identity工作流程,此处使用Register进行测试,不细看Debug过程,只看结果。
https://localhost:XXXXXX/Account/Register
至此,可以证明Identity的ORM基础替换已经成功,此时的项目结构:
其他安全和权限类配置可根据使用场景阅读Microsoft Docs自定义开发