.net core2.0下使用Identity改用dapper存储数据

前言、

  已经好多天没写博客了,鉴于空闲无聊之时又兴起想写写博客,也当是给自己做个笔记。过了这么些天,我的文笔还是依然那么烂就请多多谅解了。今天主要是分享一下在使用.net core2.0下的实际遇到的情况。在使用webapi时用了identity做用户验证。官方文档是的是用EF存储数据来使用dapper,因为个人偏好原因所以不想用EF。于是乎就去折腾。改成使用dapper做数据存储。于是就有了以下的经验。

一、使用Identity服务

  先找到Startup.cs 这个类文件 找到 ConfigureServices 方法

services.AddIdentity<ApplicationUser, ApplicationRole>().AddDefaultTokenProviders();//添加Identity
services.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 是自定义提供用户的所有数据操作的方法的类它需要继承三个接口:IUserStoreIUserPasswordStoreIUserEmailStore

  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 如下:


  [Authorize]
  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。

  接着来实现一下简单的登录登出。


        /// <summary>/// 登录        /// </summary>      
       [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();}


        /// <summary>/// 登出        /// </summary>/// <returns></returns>        [HttpPost]public async Task<IActionResult> LogOut(){await _signInManager.SignOutAsync();var json = new JsonResultModel<object>(){code = "200",data = null,message = "登出成功",remark = string.Empty};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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何解决vuepress部署出现样式问题

以前在安装hexo的时候出了样式问题&#xff0c;现在用vuepress也出现了相同的问题。 本地测试完全可以 然而打包之后就彻底乱了 即使是自己本地打包成dist之后也会出现相同的问题 有点困扰&#xff0c;应该是打包配置的问题 通过修改index.html里的内容。将/改为./ 发现部…

想使用Docker容器?先看看这些注意事项

Docker容器无疑是最近十年来最引人注目的技术之一&#xff0c;因为有了它&#xff0c;对我们思考设计、开发和运维软件的方式产生了非常有益的影响。 但是就像每一个开发工具一样&#xff0c;为了充分利用这些工具&#xff0c;需要注意一些使用中问题&#xff0c;Docker容器也是…

Vs Code如何自定义设置一键代码补全

有时候是不是看到别人输入一个vue就能打印整个代码&#xff0c;感觉很神奇&#xff0c;本文就以vue为案例教你如何使用这种骚操作&#xff01;&#xff01;&#xff01; 点击文件->首选项->用户代码片段 输入vue.json&#xff08;如果没有则新建代码片段&#xff09; &…

Realm发布Realm .NET,扩展支持.NET技术栈

继去年夏天Realm引入对.NET Core的支持&#xff0c;使开发者可以用C#来构建移动应用之后&#xff0c;Realm发布了Realm .NET。Realm .NET是一个可以让开发者更好地集成他们的.NET技术栈的新组件集。 其中一个组件&#xff0c;是针对.NET的Global Notifier&#xff0c;可以实现大…

居中对齐

自绝父相 现在有一个父盒子和一个子盒子 要想让子盒子相对父盒子居中很简单&#xff0c;在子盒子上加上属性即可 margin: 0 auto;如果说要变成水平垂直居中呢&#xff0c;加上两个auto?结果肯定是不行的 得这样 用到所谓得子绝父相 首先父亲要相对定位 然后儿子设置成这样 l…

IdentityServer4(10)- 添加对外部认证的支持之QQ登录

前言 前面我们提到过IdentityServer4是可以添加外部认证的&#xff0c;如果外部认证支持OAuth2&#xff0c;那么添加到IdentityServer4是非常简单的&#xff0c;在ASP.NET Core下提供了非常多的外部认证实现&#xff0c;比如Google&#xff0c;Facebook&#xff0c;Twitter&…

springboot 多数据源mybatis的两种整合方法

转载自 springboot-mybatis多数据源的两种整合方法 简介&#xff1a; 随着并发量的不断增加&#xff0c;显然单个数据库已经承受不了高并发带来的压力。一个项目使用多个数据库&#xff08;无论是主从复制- - 读写分离还是分布式数据库结构&#xff09;的重要性变得越来越明显…

项目实战+感慨

已经好久没写博客了&#xff0c;自从接触了项目以后&#xff0c;发现很难再挤出时间来写博客&#xff0c;大部分时间都是在关注项目的进展&#xff0c;以及查阅相关的资料。我想这也是很多程序员入职以后就很少写博客的原因。 前言 最近一段时间我接触了很多前端的东西&#x…

解决mybatis generator无法覆盖XML

转载自 解决mybatis generator无法覆盖XML 今天发现mybatis generator maven plugin在重复生成的时候xml文件只会merge&#xff0c;不会覆盖。 明明在pom.xml中配置了如下&#xff1a; <configuration><configurationFile>src/main/resources/mybatis/generato…

中间件中渲染Razor视图

前言 上一篇文章《ASP.NET Core 奇技淫巧&#xff08;1&#xff09;&#xff1a;中间件实现服务端静态化缓存》中介绍了中间件的使用方法、以及使用中间件实现服务端静态化缓存的功能。本系列文章取名“奇技淫巧”不是没道理的&#xff0c;因为这写技巧都是我最近在做的公司实际…

解决idea启动项目报错:Unable to open debugger port(127.0.0.1:60157):java.net.SocketExceptionsocket closed

转载自 解决idea启动项目报错:Unable to open debugger port(127.0.0.1:60157):java.net.SocketException"socket closed 1.问题描述: 工作当中免不了要重启服务,debug模式下偶尔启动项目,却启动失败报错: Unable to open debugger port (127.0.0.1:60157): java.net.S…

下一个计划 : .NET/.NET Core应用性能管理

前言 最近几个月一直在研究开源的APM和监控方案&#xff0c;并对比使用了Zipkin,CAT,Sky-walking,PinPoint(仅对比,未实际部署),Elastic APM,TICK Stack,Prometheus等开源产品&#xff0c;其中不乏功能强大的监控和追踪系统&#xff0c;但它们都对.NET/.NET Core没有支持或支持…

架构演化:云原生时代开启之系列一演化篇

信息技术从出现伊始到渐成主流&#xff0c;其趋势经历了软件、开源和云三个阶段&#xff1a; 软件改变世界。纵观人类社会漫长的发展历程&#xff0c;农耕时代、工业时代与信息时代可谓是三个明显分水岭&#xff0c;每个时代人类涉及的领域范畴均喷井式增长。作为信息时代最重要…

laravel部署到服务器显示Permission denied

解决这个问题可以先cd到项目根目录中 依次输入以下两个命令 find storage -type d -exec chmod 777 {} \;find storage -type f -exec chmod 777 {} \;不报错就证明成功了

基于OIDC(OpenID Connect)的SSO

在[认证授权]系列博客中&#xff0c;分别对OAuth2和OIDC在理论概念方面进行了解释说明&#xff0c;其间虽然我有写过一个完整的示例&#xff08;https://github.com/linianhui/oidc.example&#xff09;&#xff0c;但是却没有在实践方面做出过解释。在这里新开一个系列博客&am…

Consul集群搭建

转载自 Consul集群搭建 概述 作为服务发现的几种产品&#xff0c;比较可以查看这里。Consul官方也提供了几种产品之间的比较&#xff0c;点击查看。 服务发现产品 Consul有很多组件&#xff0c;但总体来说&#xff0c;它是一个发现和配置服务工具&#xff0c;特性&#xff…

js遍历对象的key和value

如果想要得到数组的键值对&#xff0c;可以用以下方法 object {"name":"kejin","age":"18"}for(var index in object){console.log(index);console.log(object[index]); }

使用Identity Server 4建立Authorization Server (6) - js(angular5) 客户端

预备知识: 学习Identity Server 4的预备知识 第一部分: 使用Identity Server 4建立Authorization Server (1) 第二部分: 使用Identity Server 4建立Authorization Server (2) 第三部分: 使用Identity Server 4建立Authorization Server (3) 第四部分: 使用Identity Server 4建立…

SpringBoot整合kafka(实现producer和consumer)

转载自 SpringBoot整合kafka(实现producer和consumer) 在Windows环境下安装运行Kafka&#xff1a;https://www.jianshu.com/p/d64798e81f3b 本文代码使用的是Spring Boot 2.1.1.RELEASE 版本 <parent><groupId>org.springframework.boot</groupId><art…

ASP.NET Core 认证与授权[7]:动态授权

基于资源的授权 有些场景下&#xff0c;授权需要依赖于要访问的资源&#xff0c;例如&#xff1a;每个资源通常会有一个创建者属性&#xff0c;我们只允许该资源的创建者才可以对其进行编辑&#xff0c;删除等操作&#xff0c;这就无法通过[Authorize]特性来指定授权了。因为授…