asp.net core identity学习1

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类的内容

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>
  1. 在Models文件夹下创建AppUser类,继承自IdentityUser
using Microsoft.AspNetCore.Identity;

namespace IdentityDemo.Models
{
    public class AppUser:IdentityUser
    {
    }
}

  1. 在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)
        {

        }
    }
}

  1. 配置数据库连接
    在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": "*"
  }

  1. 在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?}");
            });
        }
    }
}

  1. 添加数据库迁移
add-migrations InitialCreate  
update database
  1. 列举用户账户
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. 创建用户
    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; }
    }
  1. 添加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);
}
  1. 创建用户测试
  1. ctrl+F5运行程序,访问 "https://localhost:44382/Admin/Create" ,填写用户名Joe,邮箱:[email protected],密码:Secret123$。点击"创建",创建用户成功。
  2. 再次输入相同的用户名,提示“User name 'Joe' is already taken.”
  3. 更改第一步中的用户名为Alice,密码为secret,创建用户时会提示密码强度不够的信息。因为Asp.net内置密码验证规则。
  1. 更改密码验证规则
    在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();
}
  1. 自定义密码验证器类
    自定义密码验证规则除了上面一种方法,还可以自定义类,实现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. 用户名验证码规则
    用户名验证规则有两种:通过配置和自定义验证类。

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. 编辑、删除用户功能
    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>

猜你喜欢

转载自www.cnblogs.com/AlexanderZhao/p/12771111.html