ASP.NET Identity 学习

  1. 创建一个Asp.net core mvc项目
    添加Nuget包:

    • Microsoft.EntityFrameworkCore.SqlServer 3.1.3
    • Microsoft.EntityFrameworkCore.Tools 3.1.3
    • Microsoft.AspNetCore.Identity.EntityFrameworkCore 3.1.3
  2. 更改HomeController类的内容

  1. public IActionResult Index()
  2. {
  3. return View(new Dictionary<string, object> { ["Placeholder"]="Placeholder"});
  4. }

更改HomeController的Index视图内容:

  1. @{
  2. ViewData["Title"] = "首页";
  3. }
  4. @model Dictionary<string, object>
  5. <div class="bg-primary m-1 p-1 text-white"><h4>用户详情</h4></div>
  6. <table class="table table-sm table-bordered m-1 p-1">
  7. @foreach (var kvp in Model)
  8. {
  9. <tr><th>@kvp.Key</th><td>@kvp.Value</td></tr>
  10. }
  11. </table>
  1. 在Models文件夹下创建AppUser类,继承自IdentityUser
  1. using Microsoft.AspNetCore.Identity;
  2. namespace IdentityDemo.Models
  3. {
  4. public class AppUser:IdentityUser
  5. {
  6. }
  7. }
  1. 在Model文件夹下创建DbContext:AppIdentityDbContext
  1. using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
  2. using Microsoft.EntityFrameworkCore;
  3. namespace IdentityDemo.Models
  4. {
  5. public class AppIdentityDbContext:IdentityDbContext<AppUser>
  6. {
  7. public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options):base(options)
  8. {
  9. }
  10. }
  11. }
  1. 配置数据库连接
    在appsettings.json中配置数据库连接
  1. {
  2. "Data": {
  3. "IdentityDemo": {
  4. "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=IdentityDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
  5. },
  6. "Logging": {
  7. "LogLevel": {
  8. "Default": "Information",
  9. "Microsoft": "Warning",
  10. "Microsoft.Hosting.Lifetime": "Information"
  11. }
  12. },
  13. "AllowedHosts": "*"
  14. }
  1. 在Startup.cs中读取配置文件中的数据库链接地址
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using IdentityDemo.Models;
  6. using Microsoft.AspNetCore.Builder;
  7. using Microsoft.AspNetCore.Hosting;
  8. using Microsoft.AspNetCore.HttpsPolicy;
  9. using Microsoft.AspNetCore.Identity;
  10. using Microsoft.EntityFrameworkCore;
  11. using Microsoft.Extensions.Configuration;
  12. using Microsoft.Extensions.DependencyInjection;
  13. using Microsoft.Extensions.Hosting;
  14. namespace IdentityDemo
  15. {
  16. public class Startup
  17. {
  18. public Startup(IConfiguration configuration)
  19. {
  20. Configuration = configuration;
  21. }
  22. public IConfiguration Configuration { get; }
  23. // This method gets called by the runtime. Use this method to add services to the container.
  24. public void ConfigureServices(IServiceCollection services)
  25. {
  26. //配置数据库连接
  27. services.AddDbContext<AppIdentityDbContext>(
  28. options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"])
  29. );
  30. //配置Identity
  31. services.AddIdentity<AppUser, IdentityRole>()
  32. .AddEntityFrameworkStores<AppIdentityDbContext>()
  33. .AddDefaultTokenProviders();
  34. services.AddControllersWithViews();
  35. }
  36. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  37. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  38. {
  39. app.UseStatusCodePages();
  40. if (env.IsDevelopment())
  41. {
  42. app.UseDeveloperExceptionPage();
  43. }
  44. else
  45. {
  46. app.UseExceptionHandler("/Home/Error");
  47. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  48. app.UseHsts();
  49. }
  50. app.UseHttpsRedirection();
  51. app.UseStaticFiles();
  52. app.UseRouting();
  53. app.UseAuthorization();
  54. app.UseEndpoints(endpoints =>
  55. {
  56. endpoints.MapControllerRoute(
  57. name: "default",
  58. pattern: "{controller=Home}/{action=Index}/{id?}");
  59. });
  60. }
  61. }
  62. }
  1. 添加数据库迁移
  1. add-migrations InitialCreate
  2. update database
  1. 列举用户账户
  1. using IdentityDemo.Models;
  2. using Microsoft.AspNetCore.Identity;
  3. using Microsoft.AspNetCore.Mvc;
  4. namespace IdentityDemo.Controllers
  5. {
  6. public class AdminController : Controller
  7. {
  8. private UserManager<AppUser> userManager;
  9. //构造函数注入,获取UserManager
  10. public AdminController(UserManager<AppUser> usrMgr)
  11. {
  12. userManager = usrMgr;
  13. }
  14. public IActionResult Index()
  15. {
  16. return View(userManager.Users);
  17. }
  18. }
  19. }

视图修改 Index.cshtml:

  1. @model IEnumerable<AppUser>
  2. @{
  3. ViewData["Title"] = "Index";
  4. }
  5. <div class="bg-primary m-1 p-1 text-white"><h4>用户账号</h4></div>
  6. <table class="table table-sm table-bordered">
  7. <tr><th>ID</th><th>用户名</th><th>邮箱</th></tr>
  8. @if (Model.Count() == 0)
  9. {
  10. <tr><td colspan="3" class="text-center">没有</td></tr>
  11. }
  12. else
  13. {
  14. foreach (AppUser user in Model)
  15. {
  16. <tr>
  17. <td>@user.Id</td>
  18. <td>@user.UserName</td>
  19. <td>@user.Email</td>
  20. </tr>
  21. }
  22. }
  23. </table>
  24. <a class="btn btn-primary" asp-action="Create">创建</a>
  1. 创建用户
    1). 创建用户视图模型 UserViewModels
  1. public class CreateModel
  2. {
  3. [Required]
  4. [Display(Name = "用户名")]
  5. public string Name { get; set; }
  6. [Required]
  7. [DataType(DataType.EmailAddress)]
  8. [Display(Name = "电子邮箱")]
  9. public string Email { get; set; }
  10. [Required]
  11. [DataType(DataType.Password)]
  12. [Display(Name="密码")]
  13. public string Password { get; set; }
  14. }
  1. 添加Action方法
    在AdminController中添加Create方法:
  1. /// <summary>
  2. /// 创建用户
  3. /// </summary>
  4. /// <returns></returns>
  5. public ViewResult Create() => View();
  6. [HttpPost]
  7. public async Task<IActionResult> Create(CreateModel model)
  8. {
  9. if (ModelState.IsValid)
  10. {
  11. AppUser user = new AppUser
  12. {
  13. UserName = model.Name,
  14. Email = model.Email
  15. };
  16. ///创建用户
  17. IdentityResult result = await userManager.CreateAsync(user, model.Password);
  18. if (result.Succeeded) //成功则返回列表页
  19. {
  20. return RedirectToAction("Index");
  21. }
  22. else
  23. {
  24. foreach (IdentityError error in result.Errors)
  25. {
  26. ModelState.AddModelError("", error.Description);
  27. }
  28. }
  29. }
  30. return View(model);
  31. }
  1. 创建用户测试
  1. ctrl+F5运行程序,访问 “https://localhost:44382/Admin/Create” ,填写用户名Joe,邮箱:joe@example.com,密码:Secret123$。点击”创建”,创建用户成功。
  2. 再次输入相同的用户名,提示“User name ‘Joe’ is already taken.”
  3. 更改第一步中的用户名为Alice,密码为secret,创建用户时会提示密码强度不够的信息。因为Asp.net内置密码验证规则。
  1. 更改密码验证规则
    在Startup类的ConfigureServices方法中,配置密码验证规则:
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //配置数据库连接
  4. services.AddDbContext<AppIdentityDbContext>(
  5. options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"])
  6. );
  7. //配置Identity的密码验证规则
  8. //规则为至少六位
  9. services.AddIdentity<AppUser, IdentityRole>(opts =>
  10. {
  11. opts.Password.RequiredLength = 6;
  12. opts.Password.RequireNonAlphanumeric = false;
  13. opts.Password.RequireLowercase = false;
  14. opts.Password.RequireUppercase = false;
  15. opts.Password.RequireDigit = false;
  16. }).AddEntityFrameworkStores<AppIdentityDbContext>()
  17. .AddDefaultTokenProviders();
  18. services.AddControllersWithViews();
  19. }
  1. 自定义密码验证器类
    自定义密码验证规则除了上面一种方法,还可以自定义类,实现IPasswordValidator接口或者继承自UserValidator,接口定义:
  1. using System.Threading.Tasks;
  2. namespace Microsoft.AspNetCore.Identity {
  3. public interface IPasswordValidator<TUser> where TUser : class {
  4. Task<IdentityResult> ValidateAsync(UserManager<TUser> manager,
  5. TUser user, string password);
  6. }
  7. }

CustomPasswordValidator类:

  1. using Microsoft.AspNetCore.Identity;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using IdentityDemo.Models;
  6. namespace IdentityDemo.Infrastructure
  7. {
  8. /// <summary>
  9. /// 自定义用户密码验证规则
  10. /// </summary>
  11. public class CustomPasswordValidator : UserValidator<AppUser>
  12. {
  13. public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user)
  14. {
  15. IdentityResult result = await base.ValidateAsync(manager, user);
  16. List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
  17. if (!user.Email.ToLower().EndsWith("@example.com"))
  18. {
  19. errors.Add(new IdentityError
  20. {
  21. Code = "EmailIdentityError",
  22. Description = "只允许example.com的邮箱地址注册账号"
  23. });
  24. }
  25. return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
  26. }
  27. }
  28. }

在Startup类的ConfigureServices中注入服务:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //自定义密码验证服务
  4. services.AddTransient<IPasswordValidator<AppUser>, CustomPasswordValidator>();
  5. //配置数据库连接
  6. services.AddDbContext<AppIdentityDbContext>(
  7. options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"])
  8. );
  9. //配置Identity
  10. services.AddIdentity<AppUser, IdentityRole>(opts =>
  11. {
  12. opts.Password.RequiredLength = 6;
  13. opts.Password.RequireNonAlphanumeric = false;
  14. opts.Password.RequireLowercase = false;
  15. opts.Password.RequireUppercase = false;
  16. opts.Password.RequireDigit = false;
  17. }).AddEntityFrameworkStores<AppIdentityDbContext>()
  18. .AddDefaultTokenProviders();
  19. services.AddControllersWithViews();
  20. }
  1. 用户名验证码规则
    用户名验证规则有两种:通过配置和自定义验证类。

1). 通过配置,在Startup类的ConfigureServices方法中配置

  1. //配置Identity
  2. services.AddIdentity<AppUser, IdentityRole>(opts =>
  3. {
  4. opts.User.RequireUniqueEmail = true;
  5. opts.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyz";
  6. opts.Password.RequiredLength = 6;
  7. opts.Password.RequireNonAlphanumeric = false;
  8. opts.Password.RequireLowercase = false;
  9. opts.Password.RequireUppercase = false;
  10. opts.Password.RequireDigit = false;
  11. }).AddEntityFrameworkStores<AppIdentityDbContext>()
  12. .AddDefaultTokenProviders();

2). 自定义验证规则类,实现IUserValidator接口

  1. using Microsoft.AspNetCore.Identity;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using IdentityDemo.Models;
  6. namespace IdentityDemo.Infrastructure
  7. {
  8. /// <summary>
  9. /// 自定义用户名或者邮箱验证规则
  10. /// </summary>
  11. public class CustomUserValidator : UserValidator<AppUser>
  12. {
  13. public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user)
  14. {
  15. IdentityResult result = await base.ValidateAsync(manager, user);
  16. List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
  17. if (!user.Email.ToLower().EndsWith("@example.com"))
  18. {
  19. errors.Add(new IdentityError
  20. {
  21. Code = "EmailIdentityError",
  22. Description = "只允许example.com的邮箱地址注册账号"
  23. });
  24. }
  25. return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
  26. }
  27. }
  28. }

在Startup类中,配置依赖注入:

  1. services.AddTransient<IUserValidator<AppUser>,CustomUserValidator>();
  1. 编辑、删除用户功能
    1). 在用户列表页,添加编辑、删除按钮:Index.cshtml:
  1. @model IEnumerable<AppUser>
  2. @{
  3. ViewData["Title"] = "Index";
  4. }
  5. <div class="bg-primary m-1 p-1 text-white"><h4>用户账号</h4></div>
  6. <table class="table table-sm table-bordered">
  7. <tr><th>ID</th><th>用户名</th><th>邮箱</th><th>操作</th></tr>
  8. @if (Model.Count() == 0)
  9. {
  10. <tr><td colspan="3" class="text-center">没有</td></tr>
  11. }
  12. else
  13. {
  14. foreach (AppUser user in Model)
  15. {
  16. <tr>
  17. <td>@user.Id</td>
  18. <td>@user.UserName</td>
  19. <td>@user.Email</td>
  20. <td>
  21. <form asp-action="Delete" asp-route-id="@user.Id" method="post">
  22. <a class="btn btn-sm btn-primary" asp-action="Edit"
  23. asp-route-id="@user.Id">编辑</a>
  24. <button type="submit"
  25. class="btn btn-sm btn-danger">
  26. 删除
  27. </button>
  28. </form>
  29. </td>
  30. </tr>
  31. }
  32. }
  33. </table>
  34. <a class="btn btn-primary" asp-action="Create">创建</a>

2). 删除用户

  1. //删除用户
  2. [HttpPost]
  3. public async Task<IActionResult> Delete(string id)
  4. {
  5. AppUser user = await userManager.FindByIdAsync(id);
  6. if (user != null)
  7. {
  8. IdentityResult result = await userManager.DeleteAsync(user);
  9. if (result.Succeeded)
  10. {
  11. return RedirectToAction("Index");
  12. }
  13. else
  14. {
  15. AddErrorsFromResult(result);
  16. }
  17. }
  18. else
  19. {
  20. ModelState.AddModelError("", "User Not Found");
  21. }
  22. return View("Index", userManager.Users);
  23. }
  24. private void AddErrorsFromResult(IdentityResult result)
  25. {
  26. foreach (IdentityError error in result.Errors)
  27. {
  28. ModelState.AddModelError("", error.Description);
  29. }
  30. }

3). 编辑用户

  1. /// <summary>
  2. /// 编辑用户
  3. /// </summary>
  4. /// <param name="id"></param>
  5. /// <returns></returns>
  6. public async Task<IActionResult> Edit(string id)
  7. {
  8. AppUser user = await userManager.FindByIdAsync(id);
  9. if (user != null)
  10. {
  11. return View(user);
  12. }
  13. else
  14. {
  15. return RedirectToAction("Index");
  16. }
  17. }
  18. /// <summary>
  19. /// 编辑用户
  20. /// </summary>
  21. /// <param name="id"></param>
  22. /// <param name="email"></param>
  23. /// <param name="password"></param>
  24. /// <returns></returns>
  25. [HttpPost]
  26. public async Task<IActionResult> Edit(string id, string email,
  27. string password)
  28. {
  29. AppUser user = await userManager.FindByIdAsync(id);
  30. if (user != null)
  31. {
  32. user.Email = email;
  33. //用户邮箱校验
  34. IdentityResult validEmail = await userValidator.ValidateAsync(userManager, user);
  35. if (!validEmail.Succeeded)
  36. {
  37. AddErrorsFromResult(validEmail);
  38. }
  39. IdentityResult validPass = null;
  40. if (!string.IsNullOrEmpty(password))
  41. {
  42. //用户密码校验
  43. validPass = await passwordValidator.ValidateAsync(userManager, user, password);
  44. if (validPass.Succeeded)
  45. {
  46. //用户密码加密
  47. user.PasswordHash = passwordHasher.HashPassword(user, password);
  48. }
  49. else
  50. {
  51. AddErrorsFromResult(validPass);
  52. }
  53. }
  54. //1. 只修改了邮箱,2. 修改了邮箱和密码
  55. if ((validEmail.Succeeded && validPass == null) || (validEmail.Succeeded && password != string.Empty && validPass.Succeeded))
  56. {
  57. IdentityResult result = await userManager.UpdateAsync(user); //更新用户信息s
  58. if (result.Succeeded)
  59. {
  60. return RedirectToAction("Index");
  61. }
  62. else
  63. {
  64. AddErrorsFromResult(result);
  65. }
  66. }
  67. }
  68. else
  69. {
  70. ModelState.AddModelError("", "User Not Found");
  71. }
  72. return View(user);
  73. }

编辑用户的视图:
Edit.cshtml:

  1. @model AppUser
  2. @{
  3. ViewData["Title"] = "修改用户信息";
  4. }
  5. <div class="bg-primary m-1 p-1"><h4>修改用户信息</h4></div>
  6. <div asp-validation-summary="All" class="text-danger"></div>
  7. <form asp-action="Edit" method="post">
  8. <div class="form-group">
  9. <label asp-for="Id"></label>
  10. <input asp-for="Id" class="form-control" disabled />
  11. </div>
  12. <div class="form-group">
  13. <label asp-for="Email"></label>
  14. <input asp-for="Email" class="form-control" />
  15. </div>
  16. <div class="form-group">
  17. <label for="password">Password</label>
  18. <input name="password" class="form-control" />
  19. </div>
  20. <button type="submit" class="btn btn-primary">保存</button>
  21. <a asp-action="Index" class="btn btn-secondary">取消</a>
  22. </form>

版权声明:本文为AlexanderZhao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/AlexanderZhao/p/12771111.html