.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 是自定义提供用户的所有数据操作的方法的类它需要继承三个接口:IUserStore,IUserPasswordStore,IUserEmailStore

IUserStore<TUser>接口是在用户存储中必须实现的唯一接口。 它定义了用于创建、 更新、 删除和检索用户的方法。

IUserPasswordStore<TUser>接口定义实现以保持经过哈希处理的密码的方法。 它包含用于获取和设置工作经过哈希处理的密码,以及用于指示用户是否已设置密码的方法的方法。

IUserEmailStore<TUser>接口定义实现以存储用户电子邮件地址的方法。 它包含用于获取和设置的电子邮件地址和是否确认电子邮件的方法。

这里跟.net core 1.0的实现接口方式有点不同。需要多实现 IUserEmailStore 才能不报错

具体代码如下。以供大家参考。

CustomUserStore

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

  public 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即可。

DapperUsersTable

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

  public 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;//设置密码长度最小为6
    options.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 settings
    options.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/AccessDenied
    options.SlidingExpiration = true;
   });

五、其他

在实现的过程中遇到一些小状况。例如Identity不生效。是因为未在app.UseMvc() 之前使用造成的。 如果未登录会造成跳转。后来查看了.net core Identity 的源码后 发现 如果是ajax情况下 不会跳转而时 返回401的状态码页面。

然后就是Idenetity的密码加密 是用 PasswordHasher 这个类去加密的。如果想用自己的加密方式。只能通过继承接口去更改原本的方式。然后大致说到这么些。也当是给自己做做笔记。做得不好请大家多给点意见。多多谅解。谢谢。

以上这篇.net core2.0下使用Identity改用dapper存储数据(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解ASP.NET Core 之 Identity 入门(三)

    前言 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序在处理身份验证和授权有了很多的变化,多了比如手机端,平板等,所以那个时候为了适应这种变化就引入了ASP.NET Membership,但是随着时间的发展一些社交网站或者程序聚集了大量的用户,比如Facebook,Twitter,QQ等,这个时候用户希望能够使用他们在这些社交站点身份来登陆当前网站,这样可以免除注册这些琐碎而又必要的操作,用户也不必记住大量的账户密码. 又随着互联网的发展,越来越多的开发者不只是关注具体业务

  • 详解ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OWIN的东西,所以很多初学者在学习来很费劲,对于 Identity 都是一头雾水,包括我也是,曾经在学 identity 这个东西前后花了一个多月来搞懂里面的原理.所以大部分开发者对于 Identity 并没有爱,也并没有使用它,会觉得被绑架. 值得庆幸的是,在 ASP.NET Core 中,由于对模

  • 详解ASP.NET Core 之 Identity 入门(二)

    前言 在 上篇文章 中讲了关于 Identity 需要了解的单词以及相对应的几个知识点,并且知道了Identity处在整个登入流程中的位置,本篇主要是在 .NET 整个认证系统中比较重要的一个环节,就是 认证(Authentication),因为想要把 Identity 讲清楚,是绕不过 Authentication 的. 其实 Identity 也是认证系统的一个具体使用,大家一定要把 Authentication 和 Identity 当作是两个东西,一旦混淆,你就容易陷入进去. 下面就来说

  • .net core2.0下使用Identity改用dapper存储数据(实例讲解)

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

  • 对Linux下shell编程之for循环的实例讲解

    linux 下 for 循环中可以使用 break 和 continue 关键字来跳出循环, 和java 用法一致 一.常用for循环结构 #语法一 for 变量 in 值1 值2 值3.. do 程序块儿 done # #语法二 for 变量 `命令` do 程序块儿 done # #语法三 for ((初始值; 循环控制; 变量变化)) do 程序块儿 done 二.常用测试结构 1. 输出3次uptime #!/bin/bash for i in 1 2 3 4 5 do echo "$i

  • vuejs2.0子组件改变父组件的数据实例

    在vue2.0之后的版本中,不允许子组件直接改变父组件的数据,在1.0的版本中可以这样操作的,但是往往项目需求需要改变父组件的数据,2.0也是可一个,区别是,当我们把父元素的数据给子组件时,需要传一个对象,子组件通过访问对象中的属性操作数据,下面是演示 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document

  • Vue2.0基于vue-cli+webpack Vuex的用法(实例讲解)

    在这之前,我已经分享过组件与组件的通信机制以及父子组件之间的通信机制,而我们的vuex就是为了解决组件通信问题的 vuex是什么东东呢? 组件通信的本质其实就是在组件之间传递数据或组件的状态(这里将数据和状态统称为状态),但可以看到如果我们通过最基本的方式来进行通信,一旦需要管理的状态多了,代码就会变得十分臃肿和庞大.对所有状态的管理便会显得力不从心,因此,vuex出现了,他就是帮助我们把公用的状态全抽出来放在vuex的容器中,然后根据一定的规则来进行管理,我们赶紧来用一下吧,想要掌握vuex的

  • Centos7系统下搭建.NET Core2.0+Nginx+Supervisor环境

    一.Linux .NET Core简介 一直以来,微软只对自家平台提供.NET支持,这样等于让这个"理论上"可以跨平台的框架在Linux和macOS上的支持只能由第三方项目提供(比如Mono .NET). 直到微软推出完全开源的.NET Core.这个开源的平台兼容.NET  Standard,并且能在Windows.Linux和MacOS上提供完全一致的API.虽然这个小巧的.NET框架只是标准.NET的一个子集,但是已经相当强大了. 一方面,这个小巧的框架可以让某些功能性应用同时运

  • CodeFirst从零开始搭建Asp.Net Core2.0网站

    一步步教大家如何搭建Asp.Net Core2.0网站,以下所有都是建立在.NETCore2.0环境已经搭建好 右键解决方案>新建项目> 选择Web>ASP.NETCoreWeb应用程序(.NET Core) 选择Web应用程序,暂时不选择启用Docker,身份验证选择个人用户账户(会自动生成一系列和用户认证的代码) 随后生代码层次目录如下: 其中会包含身份信息的相关实现,比如相关实体信息(user)之类的,如果想对扩展微软自动的生成的用户实体类,可在Models中的Applicatio

  • IOS swift3.0 下闭包语法整理

    IOS swift3.0 下闭包语法整理 一.闭包的概念 有oc基础的都知道,闭包其实是oc里面的block,语法格式不一样,但作用是一样的.主要是用于callBack(异步回调)或者两个类之间的通信.它的本质一个函数,一个可执行的代码块,只是这个函数是没有名字的,也就是匿名函数.你也可以把他看作如 int.float一样,是一种数据类型,一种可以作为参数传递的数据类型. 二.基本语法 1.闭包的声明 //定义一个求和闭包 //闭包类型:(Int,Int)->(Int) let add:(Int

  • ASP.NET 2.0下的条件编译

    在Web开发中测试单个页面的功能实在是太麻烦,从首页用户名.密码进去后,经过一些操作后才可以来到你要测试的那个页面.(其实无论做什么的开发,测试单个功能都是很麻烦).抱着小心谨慎的态度,我一般喜欢写几段测一次,如果每次都兴师动众的启动整个项目来测试显然是很不经济的做法. 我一般会在Solution中新增一个用于测试用的配置,在其中增加一个"Test"之类的编译指令,然后在代码中,把一些测试条件,测试方法放到这个指令下.在开发团队还没有引进单元测试之类的概念的时候,我可不想用新增一个测试

  • CentOS 7.0下使用yum安装mysql的方法详解

    CentOS7默认数据库是mariadb,配置等用着不习惯,因此决定改成mysql,但是CentOS7的yum源中默认好像是没有mysql的.为了解决这个问题,我们要先下载mysql的repo源. 1.下载mysql的repo源 $ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2.安装mysql-community-release-el7-5.noarch.rpm包 $ sudo rpm -ivh mys

  • RedHat 9.0下安装igenus实录

    在REDHAT9.0下安装igenus bluelotus 2003.06.16 Redhat9.0+Qmail+smtp-auth+Vpopmail+MySQL+Igenus,实例:http://0874.cn/mail 一.安装环境 及准备工作 安装Redhat9.0,安装时选取安装apache.php.mysql,可省去以后自已编译安装的麻烦,mysql要注意选取mysql-devel开发包,mysql的头文件和库文件分别在/usr/include/mysql和/usr/lib/mysql

随机推荐