zoukankan      html  css  js  c++  java
  • 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,邮箱:joe@example.com,密码: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>
    
  • 相关阅读:
    JavaScript 【引用类型】RegExp类型
    JavaScript【引用类型】Function 类型
    JavaScript【引用方法】归并方法
    JavaScript【引用方法】迭代方法
    JavaScript【引用方法】位置方法
    【华为云技术分享】MongoDB经典故障系列一:数据库频繁启动失败怎么办?
    【华为云技术分享】Python面试的一些心得,与Python练习题分享
    【华为云技术分享】Linux内核发展史 (1)
    【华为云技术分享】Spring Boot 最流行的 16 条实践解读!
    【华为云技术分享】opensuse使用zypper安装软件
  • 原文地址:https://www.cnblogs.com/AlexanderZhao/p/12771111.html
Copyright © 2011-2022 走看看