.net core2.0下使用Identity改用dapper存储数据
前言、
已經好多天沒寫博客了,鑒于空閑無聊之時又興起想寫寫博客,也當是給自己做個筆記。過了這么些天,我的文筆還是依然那么爛就請多多諒解了。今天主要是分享一下在使用.net?core2.0下的實際遇到的情況。在使用webapi時用了identity做用戶驗證。官方文檔是的是用EF存儲數據來使用dapper,因為個人偏好原因所以不想用EF。于是乎就去折騰。改成使用dapper做數據存儲。于是就有了以下的經驗。
一、使用Identity服務
先找到Startup.cs?這個類文件?找到?ConfigureServices?方法
services.AddIdentity<ApplicationUser, ApplicationRole>().AddDefaultTokenProviders();//添加Identityservices.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();
string connectionString = Configuration.GetConnectionString("SqlConnectionStr");
services.AddTransient<SqlConnection>(e => new SqlConnection(connectionString));
services.AddTransient<DapperUsersTable>();
然后在 Configure?方法?的?app.UseMvc() 前加入下列代碼,net core 1.0的時候是app.UseIdentity()?現在已經棄用改為以下方法。
//使用驗證app.UseAuthentication();這里的?ApplicationUser?是自定義的一個用戶模型?具體是繼承?IdentityUser?繼承它的一些屬性
public class ApplicationUser :IdentityUser{ ? ? ?? ? ? ??public string AuthenticationType { get; set; } ? ? ? ? ? ? ? ?
? ? ? ??public bool IsAuthenticated { get; set; } ? ? ?
? ? ? ? ? ? ?
? ? ? ? public string Name { get; set; }}
這里的?CustomUserStore?是自定義提供用戶的所有數據操作的方法的類它需要繼承三個接口:IUserStore,IUserPasswordStore,IUserEmailStore
IUserStore<TUser>接口是在用戶存儲中必須實現的唯一接口。?它定義了用于創建、 更新、 刪除和檢索用戶的方法。
IUserPasswordStore<TUser>接口定義實現以保持經過哈希處理的密碼的方法。?它包含用于獲取和設置工作經過哈希處理的密碼,以及用于指示用戶是否已設置密碼的方法的方法。
IUserEmailStore<TUser>接口定義實現以存儲用戶電子郵件地址的方法。?它包含用于獲取和設置的電子郵件地址和是否確認電子郵件的方法。
這里跟.net core 1.0的實現接口方式有點不同。需要多實現?IUserEmailStore?才能不報錯
具體代碼如下。以供大家參考。
using Microsoft.AspNetCore.Identity;using System;using System.Threading.Tasks;using System.Threading;namespace YepMarsCRM.Web.CustomProvider { ? ?/// <summary>/// This store is only partially implemented. It supports user creation and find methods. ? ?/// </summary>public class CustomUserStore : IUserStore<ApplicationUser>,IUserPasswordStore<ApplicationUser>,IUserEmailStore<ApplicationUser>{ ? ? ?private readonly DapperUsersTable _usersTable; ? ? ? ?public CustomUserStore(DapperUsersTable usersTable){_usersTable = usersTable;} ? ? ? ?#region createuser
public async Task<IdentityResult> CreateAsync(ApplicationUser user,CancellationToken cancellationToken = default(CancellationToken)){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ? ?
?? ? ?return await _usersTable.CreateAsync(user);} ? ? ?
?#endregionpublic async Task<IdentityResult> DeleteAsync(ApplicationUser user,CancellationToken cancellationToken = default(CancellationToken)){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ? ? ? ? ?return await _usersTable.DeleteAsync(user);} ? ? ?
?public void Dispose(){} ? ? ? ?public Task<ApplicationUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken){ ? ? ? ? ? ?throw new NotImplementedException();} ? ? ?
??public async Task<ApplicationUser> FindByIdAsync(string userId,CancellationToken cancellationToken = default(CancellationToken)){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (userId == null) throw new ArgumentNullException(nameof(userId));Guid idGuid; ? ? ? ? ? ?if (!Guid.TryParse(userId, out idGuid)){ ? ? ? ? ? ? ? ?throw new ArgumentException("Not a valid Guid id", nameof(userId));} ? ? ? ? ? ?return await _usersTable.FindByIdAsync(idGuid);} ? ? ?
??public async Task<ApplicationUser> 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> GetEmailAsync(ApplicationUser user, CancellationToken cancellationToken){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ? ?
?? ? ?return Task.FromResult(user.Email);} ? ? ?
?public Task<bool> GetEmailConfirmedAsync(ApplicationUser user, CancellationToken cancellationToken){ ? ? ? ? ?
??throw new NotImplementedException();} ? ? ?
?public Task<string> GetNormalizedEmailAsync(ApplicationUser user, CancellationToken cancellationToken){ ? ? ? ? ? ?throw new NotImplementedException();} ? ? ?
?public Task<string> GetNormalizedUserNameAsync(ApplicationUser user, CancellationToken cancellationToken){ ? ? ? ? ? ?throw new NotImplementedException();} ? ? ?
??public Task<string> GetPasswordHashAsync(ApplicationUser user, CancellationToken cancellationToken){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ?
? ? ? ? ?return Task.FromResult(user.PasswordHash);} ? ? ?
?public Task<string> GetUserIdAsync(ApplicationUser user, CancellationToken cancellationToken){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ?
? ? ?return Task.FromResult(user.Id.ToString());} ? ? ?
?public Task<string> GetUserNameAsync(ApplicationUser user, CancellationToken cancellationToken){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ? ?
? ? ?return Task.FromResult(user.UserName);} ? ? ?
??public Task<bool> HasPasswordAsync(ApplicationUser user, CancellationToken cancellationToken){ ? ? ? ? ? ?throw new NotImplementedException();} ? ? ?
?public Task SetEmailAsync(ApplicationUser user, string email, CancellationToken cancellationToken){ ? ? ? ? ?
??throw new NotImplementedException();} ? ? ?
?public Task SetEmailConfirmedAsync(ApplicationUser user, bool confirmed, CancellationToken cancellationToken){ ? ? ? ? ?
?throw new NotImplementedException();} ? ? ?
??public Task SetNormalizedEmailAsync(ApplicationUser user, string normalizedEmail, CancellationToken cancellationToken){cancellationToken.ThrowIfCancellationRequested(); ? ? ? ? ? ?if (user == null) throw new ArgumentNullException(nameof(user)); ? ?
? ? ? ?if (normalizedEmail == null) throw new ArgumentNullException(nameof(normalizedEmail));user.NormalizedEmail = normalizedEmail; ? ? ? ? ? ?return Task.FromResult<object>(null);} ? ? ?
?public Task SetNormalizedUserNameAsync(ApplicationUser 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(ApplicationUser 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(ApplicationUser user, string userName, CancellationToken cancellationToken){ ? ? ? ? ? ?throw new NotImplementedException();} ? ? ? ?
public Task<IdentityResult> UpdateAsync(ApplicationUser user, CancellationToken cancellationToken){ ? ? ? ? ? ?return _usersTable.UpdateAsync(user);}} }
二、使用使用dapper做數據存儲
接著就是使用dapper做數據存儲。該類的方法都是通過?CustomUserStore?調用去操作數據庫的。具體代碼如下。根據實際的用戶表去操作dapper即可。
using Microsoft.AspNetCore.Identity;using System.Threading.Tasks;
using System.Threading;
using System.Data.SqlClient;
using System;
using Dapper;
using YepMarsCRM.Enterprise.DataBase.Model;
using YepMarsCRM.Enterprise.DataBase.Data;
namespace YepMarsCRM.Web.CustomProvider { ?
?public class DapperUsersTable{ ? ? ? ?
private readonly SqlConnection _connection; ? ? ? ?private readonly Sys_AccountData _sys_AccountData; ? ? ? ?public DapperUsersTable(SqlConnection connection){_connection = connection;_sys_AccountData = new Sys_AccountData();} ? ? ?
??private Sys_Account ApplicationUserToAccount(ApplicationUser user){ ? ? ? ?
? ?return new Sys_Account{Id = user.Id,UserName = user.UserName,PasswordHash = user.PasswordHash,Email = user.Email,EmailConfirmed = user.EmailConfirmed,PhoneNumber = user.PhoneNumber,PhoneNumberConfirmed = user.PhoneNumberConfirmed,LockoutEnd = user.LockoutEnd?.DateTime,LockoutEnabled = user.LockoutEnabled,AccessFailedCount = user.AccessFailedCount,};} ? ? ? ?#region createuser
public async Task<IdentityResult> CreateAsync(ApplicationUser user){ ? ? ? ? ? ?int rows = await _sys_AccountData.InsertAsync(ApplicationUserToAccount(user)); ? ? ? ? ? ?if (rows > 0){ ? ? ? ? ? ? ? ?return IdentityResult.Success;} ? ? ? ? ? ?return IdentityResult.Failed(new IdentityError { Description = $"Could not insert user {user.Email}." });} ? ? ? ?#endregionpublic async Task<IdentityResult> DeleteAsync(ApplicationUser user){ ? ? ? ? ? ?//string sql = "DELETE FROM Sys_Account WHERE Id = @Id"; ? ? ? ? ? ?//int rows = await _connection.ExecuteAsync(sql, new { user.Id });int rows = await _sys_AccountData.DeleteForPKAsync(ApplicationUserToAccount(user)); ? ? ? ? ? ?if (rows > 0){ ? ? ? ? ? ? ? ?return IdentityResult.Success;} ? ? ? ? ? ?return IdentityResult.Failed(new IdentityError { Description = $"Could not delete user {user.Email}." });} ? ? ? ?public async Task<ApplicationUser> FindByIdAsync(Guid userId){ ? ? ? ? ? ?string sql = "SELECT * ?FROM Sys_Account WHERE Id = @Id;"; ? ? ? ? ? ?return await _connection.QuerySingleOrDefaultAsync<ApplicationUser>(sql, new{Id = userId});} ? ? ?
?public async Task<ApplicationUser> FindByNameAsync(string userName){ ? ? ? ? ? ?string sql = "SELECT * FROM Sys_Account WHERE UserName = @UserName;"; ? ? ? ? ? ?return await _connection.QuerySingleOrDefaultAsync<ApplicationUser>(sql, new{UserName = userName}); ? ? ? ? ? ?//var user = new ApplicationUser() { UserName = userName, Email = userName, EmailConfirmed = false }; ? ? ? ? ? ?//user.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(user, "test"); ? ? ? ? ? ?//return await Task.FromResult(user); ? ? ? ?} ? ? ?
? ? ? ?
? ? ? ?public async Task<IdentityResult> UpdateAsync(ApplicationUser applicationUser){ ? ? ? ? ?
??var user = ApplicationUserToAccount(applicationUser); ? ?
?? ? ?var result = await _sys_AccountData.UpdateForPKAsync(user); ? ? ? ? ?
??if (result > 0){ ? ? ? ? ? ? ?
?return IdentityResult.Success;} ? ? ? ? ? ?return IdentityResult.Failed(new IdentityError { Description = $"Could not update user {user.Email}." });}} }
三、使用UserManager、SignInManager驗證操作
新建一個?AccountController?控制器?并在構造函數中獲取?依賴注入的對象?UserManager?與?SignInManager?如下:
public class AccountController : Controller{ ? ? ? ?private readonly UserManager<ApplicationUser> _userManager; ? ? ? ?private readonly SignInManager<ApplicationUser> _signInManager; ? ? ? ?private readonly ILogger _logger;public AccountController(UserManager<ApplicationUser> userManager, ? ? ? ? ? ?SignInManager<ApplicationUser> signInManager,ILoggerFactory loggerFactory){_userManager = userManager;_signInManager = signInManager;_logger = loggerFactory.CreateLogger<AccountController>();}}
SignInManager?是提供用戶登錄登出的API ,UserManager?是提供用戶管理的API。
接著來實現一下簡單的登錄登出。
? ? ? ?[HttpPost][AllowAnonymous]public async Task<IActionResult> Login(ReqLoginModel req){var json = new JsonResultModel<object>(); ? ? ? ? ? ?if (ModelState.IsValid){ ? ? ? ? ? ? ? ?var result = await _signInManager.PasswordSignInAsync(req.UserName, req.Password, isPersistent: true, lockoutOnFailure: false); ? ? ? ? ? ? ? ?if (result.Succeeded){json.code = "200";json.message = "登錄成功";} ? ? ? ? ? ? ? ?else{json.code = "400";json.message = "登錄失敗";} ? ? ? ? ? ? ? ?if (result.IsLockedOut){json.code = "401";json.message = "賬戶密碼已錯誤3次,賬戶被鎖定,請30分鐘后再嘗試";}} ? ? ? ? ? ?else{ ? ? ? ? ? ? ? ?var errorMessges = ModelState.GetErrorMessage();json.code = "403";json.message = string.Join(",", errorMessges);} ? ? ? ? ? ?return json.ToJsonResult();}
四、使用Identity配置
在 ConfigureServices?方法中加入
services.Configure<IdentityOptions>(options =>{ ? ? ? ? ? ? ? ?// 密碼配置options.Password.RequireDigit = false;//是否需要數字(0-9).options.Password.RequiredLength = 6;//設置密碼長度最小為6options.Password.RequireNonAlphanumeric = false;//是否包含非字母或數字字符。options.Password.RequireUppercase = false;//是否需要大寫字母(A-Z).options.Password.RequireLowercase = false;//是否需要小寫字母(a-z). ? ? ? ? ? ? ? ?//options.Password.RequiredUniqueChars = 6; ? ? ? ? ? ? ? ?// 鎖定設置options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);//賬戶鎖定時長30分鐘options.Lockout.MaxFailedAccessAttempts = 3;//10次失敗的嘗試將賬戶鎖定 ? ? ? ? ? ? ? ?//options.Lockout.AllowedForNewUsers = true; ? ? ? ? ? ? ? ?// 用戶設置options.User.RequireUniqueEmail = false; //是否Email地址必須唯一 ? ? ? ? ? ?});services.ConfigureApplicationCookie(options =>{ ? ? ? ? ? ? ? ?// Cookie settingsoptions.Cookie.HttpOnly = true; ? ? ? ? ? ? ? ?//options.Cookie.Expiration = TimeSpan.FromMinutes(30);//30分鐘options.Cookie.Expiration = TimeSpan.FromHours(12);//12小時options.LoginPath = "/api/Account/NotLogin"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login ? ? ? ? ? ? ? ?//options.LogoutPath = "/api/Account/Logout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout ? ? ? ? ? ? ? ?//options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath is not set here, ASP.NET Core will default to /Account/AccessDeniedoptions.SlidingExpiration = true;});
五、其他
在實現的過程中遇到一些小狀況。例如Identity不生效。是因為未在app.UseMvc()?之前使用造成的。?如果未登錄會造成跳轉。后來查看了.net core Identity 的源碼后?發現?如果是ajax情況下?不會跳轉而時?返回401的狀態碼頁面。
然后就是Idenetity的密碼加密?是用?PasswordHasher?這個類去加密的。如果想用自己的加密方式。只能通過繼承接口去更改原本的方式。然后大致說到這么些。也當是給自己做做筆記。做得不好請大家多給點意見。多多諒解。謝謝。
原文:http://www.cnblogs.com/JinJi-Jary/p/7879024.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的.net core2.0下使用Identity改用dapper存储数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 跟着老桂学ASP.NET Core 2.
- 下一篇: 想使用Docker容器?先看看这些注意事