ASP.NET Identity 學習html
建立一個Asp.net core mvc項目
添加Nuget包:ios
更改HomeController類的內容git
public IActionResult Index() { return View(new Dictionary<string, object> { ["Placeholder"]="Placeholder"}); }
更改HomeController的Index視圖內容:sql
@{ ViewData["Title"] = "首頁"; } @model Dictionary<string, object> <div class="bg-primary m-1 p-1 text-white"><h4>用戶詳情</h4></div> <table class="table table-sm table-bordered m-1 p-1"> @foreach (var kvp in Model) { <tr><th>@kvp.Key</th><td>@kvp.Value</td></tr> } </table>
using Microsoft.AspNetCore.Identity; namespace IdentityDemo.Models { public class AppUser:IdentityUser { } }
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace IdentityDemo.Models { public class AppIdentityDbContext:IdentityDbContext<AppUser> { public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options):base(options) { } } }
{ "Data": { "IdentityDemo": { "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=IdentityDemo;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using IdentityDemo.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace IdentityDemo { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //配置數據庫鏈接 services.AddDbContext<AppIdentityDbContext>( options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"]) ); //配置Identity services.AddIdentity<AppUser, IdentityRole>() .AddEntityFrameworkStores<AppIdentityDbContext>() .AddDefaultTokenProviders(); services.AddControllersWithViews(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseStatusCodePages(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
add-migrations InitialCreate update database
using IdentityDemo.Models; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace IdentityDemo.Controllers { public class AdminController : Controller { private UserManager<AppUser> userManager; //構造函數注入,獲取UserManager public AdminController(UserManager<AppUser> usrMgr) { userManager = usrMgr; } public IActionResult Index() { return View(userManager.Users); } } }
視圖修改 Index.cshtml:數據庫
@model IEnumerable<AppUser> @{ ViewData["Title"] = "Index"; } <div class="bg-primary m-1 p-1 text-white"><h4>用戶帳號</h4></div> <table class="table table-sm table-bordered"> <tr><th>ID</th><th>用戶名</th><th>郵箱</th></tr> @if (Model.Count() == 0) { <tr><td colspan="3" class="text-center">沒有</td></tr> } else { foreach (AppUser user in Model) { <tr> <td>@user.Id</td> <td>@user.UserName</td> <td>@user.Email</td> </tr> } } </table> <a class="btn btn-primary" asp-action="Create">建立</a>
public class CreateModel { [Required] [Display(Name = "用戶名")] public string Name { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "電子郵箱")] public string Email { get; set; } [Required] [DataType(DataType.Password)] [Display(Name="密碼")] public string Password { get; set; } }
/// <summary> /// 建立用戶 /// </summary> /// <returns></returns> public ViewResult Create() => View(); [HttpPost] public async Task<IActionResult> Create(CreateModel model) { if (ModelState.IsValid) { AppUser user = new AppUser { UserName = model.Name, Email = model.Email }; ///建立用戶 IdentityResult result = await userManager.CreateAsync(user, model.Password); if (result.Succeeded) //成功則返回列表頁 { return RedirectToAction("Index"); } else { foreach (IdentityError error in result.Errors) { ModelState.AddModelError("", error.Description); } } } return View(model); }
public void ConfigureServices(IServiceCollection services) { //配置數據庫鏈接 services.AddDbContext<AppIdentityDbContext>( options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"]) ); //配置Identity的密碼驗證規則 //規則爲至少六位 services.AddIdentity<AppUser, IdentityRole>(opts => { opts.Password.RequiredLength = 6; opts.Password.RequireNonAlphanumeric = false; opts.Password.RequireLowercase = false; opts.Password.RequireUppercase = false; opts.Password.RequireDigit = false; }).AddEntityFrameworkStores<AppIdentityDbContext>() .AddDefaultTokenProviders(); services.AddControllersWithViews(); }
using System.Threading.Tasks; namespace Microsoft.AspNetCore.Identity { public interface IPasswordValidator<TUser> where TUser : class { Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password); } }
CustomPasswordValidator類:json
using Microsoft.AspNetCore.Identity; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using IdentityDemo.Models; namespace IdentityDemo.Infrastructure { /// <summary> /// 自定義用戶密碼驗證規則 /// </summary> public class CustomPasswordValidator : UserValidator<AppUser> { public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user) { IdentityResult result = await base.ValidateAsync(manager, user); List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList(); if (!user.Email.ToLower().EndsWith("@example.com")) { errors.Add(new IdentityError { Code = "EmailIdentityError", Description = "只容許example.com的郵箱地址註冊帳號" }); } return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray()); } } }
在Startup類的ConfigureServices中注入服務:c#
public void ConfigureServices(IServiceCollection services) { //自定義密碼驗證服務 services.AddTransient<IPasswordValidator<AppUser>, CustomPasswordValidator>(); //配置數據庫鏈接 services.AddDbContext<AppIdentityDbContext>( options => options.UseSqlServer(Configuration["Data:IdentityDemo:ConnectionString"]) ); //配置Identity services.AddIdentity<AppUser, IdentityRole>(opts => { opts.Password.RequiredLength = 6; opts.Password.RequireNonAlphanumeric = false; opts.Password.RequireLowercase = false; opts.Password.RequireUppercase = false; opts.Password.RequireDigit = false; }).AddEntityFrameworkStores<AppIdentityDbContext>() .AddDefaultTokenProviders(); services.AddControllersWithViews(); }
1). 經過配置,在Startup類的ConfigureServices方法中配置bash
//配置Identity services.AddIdentity<AppUser, IdentityRole>(opts => { opts.User.RequireUniqueEmail = true; opts.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyz"; opts.Password.RequiredLength = 6; opts.Password.RequireNonAlphanumeric = false; opts.Password.RequireLowercase = false; opts.Password.RequireUppercase = false; opts.Password.RequireDigit = false; }).AddEntityFrameworkStores<AppIdentityDbContext>() .AddDefaultTokenProviders();
2). 自定義驗證規則類,實現IUserValidator接口mvc
using Microsoft.AspNetCore.Identity; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using IdentityDemo.Models; namespace IdentityDemo.Infrastructure { /// <summary> /// 自定義用戶名或者郵箱驗證規則 /// </summary> public class CustomUserValidator : UserValidator<AppUser> { public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user) { IdentityResult result = await base.ValidateAsync(manager, user); List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList(); if (!user.Email.ToLower().EndsWith("@example.com")) { errors.Add(new IdentityError { Code = "EmailIdentityError", Description = "只容許example.com的郵箱地址註冊帳號" }); } return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray()); } } }
在Startup類中,配置依賴注入:app
services.AddTransient<IUserValidator<AppUser>,CustomUserValidator>();
@model IEnumerable<AppUser> @{ ViewData["Title"] = "Index"; } <div class="bg-primary m-1 p-1 text-white"><h4>用戶帳號</h4></div> <table class="table table-sm table-bordered"> <tr><th>ID</th><th>用戶名</th><th>郵箱</th><th>操做</th></tr> @if (Model.Count() == 0) { <tr><td colspan="3" class="text-center">沒有</td></tr> } else { foreach (AppUser user in Model) { <tr> <td>@user.Id</td> <td>@user.UserName</td> <td>@user.Email</td> <td> <form asp-action="Delete" asp-route-id="@user.Id" method="post"> <a class="btn btn-sm btn-primary" asp-action="Edit" asp-route-id="@user.Id">編輯</a> <button type="submit" class="btn btn-sm btn-danger"> 刪除 </button> </form> </td> </tr> } } </table> <a class="btn btn-primary" asp-action="Create">建立</a>
2). 刪除用戶
//刪除用戶 [HttpPost] public async Task<IActionResult> Delete(string id) { AppUser user = await userManager.FindByIdAsync(id); if (user != null) { IdentityResult result = await userManager.DeleteAsync(user); if (result.Succeeded) { return RedirectToAction("Index"); } else { AddErrorsFromResult(result); } } else { ModelState.AddModelError("", "User Not Found"); } return View("Index", userManager.Users); } private void AddErrorsFromResult(IdentityResult result) { foreach (IdentityError error in result.Errors) { ModelState.AddModelError("", error.Description); } }
3). 編輯用戶
/// <summary> /// 編輯用戶 /// </summary> /// <param name="id"></param> /// <returns></returns> public async Task<IActionResult> Edit(string id) { AppUser user = await userManager.FindByIdAsync(id); if (user != null) { return View(user); } else { return RedirectToAction("Index"); } } /// <summary> /// 編輯用戶 /// </summary> /// <param name="id"></param> /// <param name="email"></param> /// <param name="password"></param> /// <returns></returns> [HttpPost] public async Task<IActionResult> Edit(string id, string email, string password) { AppUser user = await userManager.FindByIdAsync(id); if (user != null) { user.Email = email; //用戶郵箱校驗 IdentityResult validEmail = await userValidator.ValidateAsync(userManager, user); if (!validEmail.Succeeded) { AddErrorsFromResult(validEmail); } IdentityResult validPass = null; if (!string.IsNullOrEmpty(password)) { //用戶密碼校驗 validPass = await passwordValidator.ValidateAsync(userManager, user, password); if (validPass.Succeeded) { //用戶密碼加密 user.PasswordHash = passwordHasher.HashPassword(user, password); } else { AddErrorsFromResult(validPass); } } //1. 只修改了郵箱,2. 修改了郵箱和密碼 if ((validEmail.Succeeded && validPass == null) || (validEmail.Succeeded && password != string.Empty && validPass.Succeeded)) { IdentityResult result = await userManager.UpdateAsync(user); //更新用戶信息s if (result.Succeeded) { return RedirectToAction("Index"); } else { AddErrorsFromResult(result); } } } else { ModelState.AddModelError("", "User Not Found"); } return View(user); }
編輯用戶的視圖:
Edit.cshtml:
@model AppUser @{ ViewData["Title"] = "修改用戶信息"; } <div class="bg-primary m-1 p-1"><h4>修改用戶信息</h4></div> <div asp-validation-summary="All" class="text-danger"></div> <form asp-action="Edit" method="post"> <div class="form-group"> <label asp-for="Id"></label> <input asp-for="Id" class="form-control" disabled /> </div> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> </div> <div class="form-group"> <label for="password">Password</label> <input name="password" class="form-control" /> </div> <button type="submit" class="btn btn-primary">保存</button> <a asp-action="Index" class="btn btn-secondary">取消</a> </form>