asp.net core identity学习1
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,邮箱:joe@example.com,密码: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>