.NET IDS4(identityService4)

文章目录

引入Identity服务,更新数据表
Ids4的注册

一.引入Identity服务,更新数据表

1.接之前写的文章Efcore教程 之前我们创建好一个AppDbContext类,继承于DbContext,现在改为IdentityDbContext,因为IdentityDbContext继承于DbContext
2.配置ASP.NET Core Identity服务
在ConfigureServices添加:
services.AddIdentity<IdentityUser,IdentityRole>().AddEntityFrameworkStores<AppDbContext>();
3.将Authorization中间件添加到请求管道,代码如下:

点击查看代码
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
           
            if (env.IsDevelopment())
            {                           
                app.UseDeveloperExceptionPage();
            }else if(env.IsStaging()||env.IsProduction()||env.IsEnvironment("UAT"))
            {
                app.UseExceptionHandler("/Error");
                app.UseStatusCodePagesWithRedirects("/Error/{0}");
            }
            app.UseStaticFiles();
            
            app.UseRouting();
            //添加验证中间件
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name:"default",
                    pattern: "{controller=Home}/{action=Index}/{id?}"
                );
            });
            
        }

顺序不能乱!
4.现在开始身份迁移,打开程序包控制台窗口 执行以下命令进行新的迁移(生成迁移文件)
Add-Migration AddingIdentity
此迁移用于创建ASP.NET CORE Identity系统所需的表的代码
如果运行,则会出现以下错误(没有在数据库上下文类中重写OnModelCreating就不会报错,可以跳过这一步), The entity type 'IdentityUserLogin<string>' requires a primary key to be defined
之前因为封装Seed()方法(生成种子数据的方法),所以重写OnModelCreating()方法,但未调用基本IdentityDbContext类OnModelCreating()方法.
Identity表的键映射在IdentityDbContext类的OnModelCreating()方法中,因此,要解决这个错误,需要做的是,调用基类OnModelCreating()使用该方法的关键字,代码如下:

点击查看代码
public class AppDbContext:IdentityDbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options):base(options)
        {

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Seed();
        }
        public DbSet<Student> Students { get; set; }
    }

5.再次执行Add-Migration AddingIdentity发现成功
执行Update-Database 命令更新数据表,即可
6.更新之后的数据表如下:

二.Ids4的注册

1.关于界面的操作我就不过多介绍了,新增一个控制器Account
2.UserManager和SignInManager提供用户登录所需的方法和登录,注销用户,将这两个服务注入到AccountController中,代码如下:

点击查看代码
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using MockSchoolManageMent.ViewModels;
using System.Threading.Tasks;

namespace MockSchoolManageMent.Controllers
{
    public class AccountController : Controller
    {
        private readonly UserManager<IdentityUser> userManager;
        private readonly SignInManager<IdentityUser> signInManager;

        public AccountController(UserManager<IdentityUser> _userManager,
          SignInManager<IdentityUser> _signInManager)
        {
            this.userManager = _userManager;
            this.signInManager = _signInManager;
        }
        [HttpGet]
        public IActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                //将数据从RegisterViewModel复制到IdentityUser
                var user = new IdentityUser
                {
                    UserName = model.Email,
                    Email = model.Email
                };
                //将用户数据存储在AspNetUsers数据库表中
                var result = await userManager.CreateAsync(user, model.Password);
                //如果成功创建用户,则使用登录服务登录用户信息
                //并重定向到HomeController的Index操作方法中(跳转到主页面)
                if (result.Succeeded)
                {
                    await signInManager.SignInAsync(user, isPersistent:false);
                    return RedirectToAction("index","home");
                }
                //如果有任何错误,将它们添加到ModelState对象中
                //将由验证摘要标记助手显示到视图中
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            return View(model);
        }
    }
}

3.启动项目之后发现

  • 密码验证机制太复杂了
  • 它是英文的,对于我们来说支持不是太友好

三.ASP.NET Core Identity密码默认设置
1.在Startup中添加

点击查看代码
services.Configure<IdentityOptions>(options =>
            {
                options.Password.RequiredLength = 6;
                options.Password.RequiredUniqueChars = 3;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.SignIn.RequireConfirmedEmail = true;
                //通过自定义的CustomEmailConfirmation名称来覆盖旧有token名称,是它与AddTokenProvider<CustomEmailConfirmationTokenProvider<ApplicationUser>>("CustomEmailConfirmation")关联在一起
                options.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
                options.Lockout.MaxFailedAccessAttempts = 5;
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
            });

2.修改中文提示的错误信息
在根目录下 添加CustomIdentityErrorDescriber类,继承于IdentityErrorDescriber

点击查看代码
using Microsoft.AspNetCore.Identity;

namespace MockSchoolManageMent
{
    public class CustomIdentityErrorDescriber : IdentityErrorDescriber
    {

        public override IdentityError DefaultError()
        {
            return new IdentityError { Code = nameof(DefaultError), Description = $"发生了未知的故障。" };
        }

        public override IdentityError ConcurrencyFailure()
        {
            return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "乐观并发失败,对象已被修改。" };
        }

        public override IdentityError PasswordMismatch()
        {
            return new IdentityError { Code = nameof(PasswordMismatch), Description = "密码错误" };
        }

        public override IdentityError InvalidToken()
        {
            return new IdentityError { Code = nameof(InvalidToken), Description = "无效的令牌." };
        }

        public override IdentityError LoginAlreadyAssociated()
        {
            return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "具有此登录的用户已经存在." };
        }

        public override IdentityError InvalidUserName(string userName)
        {
            return new IdentityError { Code = nameof(InvalidUserName), Description = $"用户名'{userName}'无效,只能包含字母或数字." };
        }

        public override IdentityError InvalidEmail(string email)
        {
            return new IdentityError { Code = nameof(InvalidEmail), Description = $"邮箱 '{email}' 无效." };
        }

        public override IdentityError DuplicateUserName(string userName)
        {
            return new IdentityError { Code = nameof(DuplicateUserName), Description = $"用户名 '{userName}' 已被使用." };
        }

        public override IdentityError DuplicateEmail(string email)
        {
            return new IdentityError { Code = nameof(DuplicateEmail), Description = $"邮箱 '{email}' 已被使用." };
        }

        public override IdentityError InvalidRoleName(string role)
        {
            return new IdentityError { Code = nameof(InvalidRoleName), Description = $"角色名 '{role}' 无效." };
        }

        public override IdentityError DuplicateRoleName(string role)
        {
            return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"角色名 '{role}' 已被使用." };
        }

        public override IdentityError UserAlreadyHasPassword()
        {
            return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "该用户已设置了密码." };
        }

        public override IdentityError UserLockoutNotEnabled()
        {
            return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "此用户未启用锁定." };
        }

        public override IdentityError UserAlreadyInRole(string role)
        {
            return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"用户已关联角色 '{role}'." };
        }

        public override IdentityError UserNotInRole(string role)
        {
            return new IdentityError { Code = nameof(UserNotInRole), Description = $"用户未关联角色 '{role}'." };
        }

        public override IdentityError PasswordTooShort(int length)
        {
            return new IdentityError { Code = nameof(PasswordTooShort), Description = $"密码必须至少是{length}字符." };
        }

        public override IdentityError PasswordRequiresNonAlphanumeric()
        {
            return new IdentityError
            {
                Code = nameof(PasswordRequiresNonAlphanumeric),
                Description = "密码必须至少有一个非字母数字字符."
            };
        }

        public override IdentityError PasswordRequiresDigit()
        {
            return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = $"密码必须至少有一个数字('0'-'9')." };
        }


        public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
        {
            return new IdentityError { Code = nameof(PasswordRequiresUniqueChars), Description = $"密码必须使用至少不同的{uniqueChars}字符。" };
        }

        public override IdentityError PasswordRequiresLower()
        {
            return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "密码必须至少有一个小写字母('a'-'z')." };
        }

        public override IdentityError PasswordRequiresUpper()
        {
            return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "密码必须至少有一个大写字母('A'-'Z')." };
        }



    }
}

3.添加修改自定义错误信息显示方法
在startup类中的ConfigureServices()方法中,在AddIdentity()服务中使用AddErrorDescriber()方法覆盖默认的错误提示内容
services.AddIdentity<IdentityUser, IdentityRole>().AddErrorDescriber<CustomIdentityErrorDescriber>().AddEntityFrameworkStores<AppDbContext>();

posted @ 2022-02-22 13:11  rookiexwang  阅读(487)  评论(1编辑  收藏  举报