asp.net core identity學習1
阿新 • • 發佈:2020-04-25
ASP.NET Identity 學習
-
建立一個Asp.net core mvc專案
新增Nuget包:- Microsoft.EntityFrameworkCore.SqlServer 3.1.3
- Microsoft.EntityFrameworkCore.Tools 3.1.3
- Microsoft.AspNetCore.Identity.EntityFrameworkCore 3.1.3
-
更改HomeController類的內容
public IActionResult Index() { return View(new Dictionary<string, object> { ["Placeholder"]="Placeholder"}); }
更改HomeController的Index檢視內容:
@{ 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>
- 在Models資料夾下建立AppUser類,繼承自IdentityUser
using Microsoft.AspNetCore.Identity;
namespace IdentityDemo.Models
{
public class AppUser:IdentityUser
{
}
}
- 在Model資料夾下建立DbContext:AppIdentityDbContext
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace IdentityDemo.Models { public class AppIdentityDbContext:IdentityDbContext<AppUser> { public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options):base(options) { } } }
- 配置資料庫連線
在appsettings.json中配置資料庫連線
{
"Data": {
"IdentityDemo": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=IdentityDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
- 在Startup.cs中讀取配置檔案中的資料庫連結地址
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>
- 建立使用者
1). 建立使用者檢視模型 UserViewModels
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; }
}
- 新增Action方法
在AdminController中新增Create方法:
/// <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);
}
- 建立使用者測試
- ctrl+F5執行程式,訪問 "https://localhost:44382/Admin/Create" ,填寫使用者名稱Joe,郵箱:[email protected],密碼:Secret123$。點選"建立",建立使用者成功。
- 再次輸入相同的使用者名稱,提示“User name 'Joe' is already taken.”
- 更改第一步中的使用者名稱為Alice,密碼為secret,建立使用者時會提示密碼強度不夠的資訊。因為Asp.net內建密碼驗證規則。
- 更改密碼驗證規則
在Startup類的ConfigureServices方法中,配置密碼驗證規則:
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();
}
- 自定義密碼驗證器類
自定義密碼驗證規則除了上面一種方法,還可以自定義類,實現IPasswordValidator介面或者繼承自UserValidator,介面定義:
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類:
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中注入服務:
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方法中配置
//配置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介面
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類中,配置依賴注入:
services.AddTransient<IUserValidator<AppUser>,CustomUserValidator>();
- 編輯、刪除使用者功能
1). 在使用者列表頁,新增編輯、刪除按鈕: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><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>