zoukankan      html  css  js  c++  java
  • asp.net core系列 47 Identity 自定义用户数据

    一.概述

             接着上篇的WebAppIdentityDemo项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Identity / Data / {项目名称}User.cs。自定义的用户数据模型属性需要使用[PersonalData]来修饰,以便自动下载和删除。使数据能够下载和删除有助于满足GDPR要求。

      1.1 自定义用户数据类 WebAppIdentityDemo.Areas.Identity.Data。

        public class WebAppIdentityDemoUser:IdentityUser
        {
            /// <summary>
            /// Full name
            /// </summary>
            [PersonalData]
            public string Name { get; set; }
    
            /// <summary>
            /// Birth Date
            /// </summary>
            [PersonalData]
            public DateTime DOB { get; set; }
        }

        使用属性修饰PersonalData特性是:

          使用Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml 页调用UserManager.Delete

          使用Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml 页下载用户数据

      1.2 修改IdentityHostingStartup

        将Startup中有关identity的服务移到该文件中,好集中管理。

       public class IdentityHostingStartup : IHostingStartup
        {
            public void Configure(IWebHostBuilder builder)
            {
                builder.ConfigureServices((context, services) => {
                    services.AddDbContext<ApplicationDbContext>(options =>
                        options.UseSqlServer(
                            context.Configuration.GetConnectionString("DefaultConnection")));
    
                    services.AddDefaultIdentity<WebAppIdentityDemoUser>()
                       .AddDefaultUI()
                       .AddEntityFrameworkStores<ApplicationDbContext>();
    
                    services.Configure<IdentityOptions>(options =>
                    {
                        // Password settings.
                        options.Password.RequireDigit = true;
                        options.Password.RequireLowercase = true;
                        options.Password.RequireNonAlphanumeric = true;
                        options.Password.RequireUppercase = true;
                        options.Password.RequiredLength = 6;
                        options.Password.RequiredUniqueChars = 1;
    
                        // Lockout settings.
                        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                        options.Lockout.MaxFailedAccessAttempts = 5;
                        options.Lockout.AllowedForNewUsers = true;
    
                        // User settings.
                        options.User.AllowedUserNameCharacters =
                        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
                        options.User.RequireUniqueEmail = false;
                    });
    
                    services.ConfigureApplicationCookie(options =>
                    {
                        // Cookie settings
                        options.Cookie.HttpOnly = true;
                        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    
                        options.LoginPath = $"/Identity/Account/Login";
                        options.LogoutPath = $"/Identity/Account/Logout";
                        options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
                    });
                });
            }
        }

      1.3 修改DbContext上下文

        // public class ApplicationDbContext : IdentityDbContext
        public class ApplicationDbContext : IdentityDbContext<WebAppIdentityDemoUser>
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                : base(options)
            {
            }
            protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
                // Customize the ASP.NET Core Identity model and override the defaults if needed.
                // For example, you can rename the ASP.NET Core Identity table names and more.
                // Add your customizations after calling base.OnModelCreating(builder);
            }
        }

      1.4 数据库版本迁移

      PM> Add-Migration IdentitySchema2
      PM> Update-Database IdentitySchema2

      1.5 更新注册页面

        在开发中,会员系统要重用修改的页面,把IdentityUser 改成WebAppIdentityDemoUser。如果没改将报错:未解析到服务IdentityUser。红色部分为修改的代码

        [AllowAnonymous]
        public class RegisterModel : PageModel
        {
            // private readonly SignInManager<IdentityUser> _signInManager;
            //private readonly UserManager<IdentityUser> _userManager;
            private readonly SignInManager<WebAppIdentityDemoUser> _signInManager;
            private readonly UserManager<WebAppIdentityDemoUser> _userManager;
    
            private readonly ILogger<RegisterModel> _logger;
            private readonly IEmailSender _emailSender;
    
            public RegisterModel(
                UserManager<WebAppIdentityDemoUser> userManager,
                SignInManager<WebAppIdentityDemoUser> signInManager,
                ILogger<RegisterModel> logger,
                IEmailSender emailSender)
            {
                _userManager = userManager;
                _signInManager = signInManager;
                _logger = logger;
                _emailSender = emailSender;
            }
    
            [BindProperty]
            public InputModel Input { get; set; }
    
            public string ReturnUrl { get; set; }
    
            public class InputModel
            {
                [Required]
                [DataType(DataType.Text)]
                [Display(Name = "Full name")]
                public string Name { get; set; }
    
                [Required]
                [Display(Name = "Birth Date")]
                [DataType(DataType.Date)]
                public DateTime DOB { get; set; }
    
    
                [Required]
                [EmailAddress]
                [Display(Name = "Email")]
                public string Email { get; set; }
    
                [Required]
                [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
                [DataType(DataType.Password)]
                [Display(Name = "Password")]
                public string Password { get; set; }
    
                [DataType(DataType.Password)]
                [Display(Name = "Confirm password")]
                [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
                public string ConfirmPassword { get; set; }
            }
    
            public void OnGet(string returnUrl = null)
            {
                ReturnUrl = returnUrl;
            }
    
            public async Task<IActionResult> OnPostAsync(string returnUrl = null)
            {
                returnUrl = returnUrl ?? Url.Content("~/");
                if (ModelState.IsValid)
                {
                    // var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
                    var user = new WebAppIdentityDemoUser
                    {
                        UserName = Input.Email,
                        Email = Input.Email,
                        Name = Input.Name,
                        DOB = Input.DOB
                    };
                    var result = await _userManager.CreateAsync(user, Input.Password);
                    if (result.Succeeded)
                    {
                        _logger.LogInformation("User created a new account with password.");
    
                        var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                        var callbackUrl = Url.Page(
                            "/Account/ConfirmEmail",
                            pageHandler: null,
                            values: new { userId = user.Id, code = code },
                            protocol: Request.Scheme);
    
                        await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                            $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
    
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                    foreach (var error in result.Errors)
                    {
                        ModelState.AddModelError(string.Empty, error.Description);
                    }
                }
    
                // If we got this far, something failed, redisplay form
                return Page();
            }
        }

      

    @page
    @model RegisterModel
    @{
        ViewData["Title"] = "Register";
    }
    
    <h1>@ViewData["Title"]</h1>
    
    <div class="row">
        <div class="col-md-4">
            <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
                <h4>Create a new account.</h4>
                <hr />
                <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group"> <label asp-for="Input.Name"></label> <input asp-for="Input.Name" class="form-control" /> <span asp-validation-for="Input.Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.DOB"></label> <input asp-for="Input.DOB" class="form-control" /> <span asp-validation-for="Input.DOB" class="text-danger"></span> </div>

    <div class="form-group"> <label asp-for="Input.Email"></label> <input asp-for="Input.Email" class="form-control" /> <span asp-validation-for="Input.Email" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.Password"></label> <input asp-for="Input.Password" class="form-control" /> <span asp-validation-for="Input.Password" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.ConfirmPassword"></label> <input asp-for="Input.ConfirmPassword" class="form-control" /> <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">Register</button> </form> </div> </div> @section Scripts { <partial name="_ValidationScriptsPartial" /> }

        启动程序,运行注册页,保存成功后,查看数据库,如下所示:

      1.6 其它相关页修改

        下面这些最基本的页面,都需要把IdentityUser 改成WebAppIdentityDemoUser。

          登录页 /Identity/Account/Login

          注册页 Identity/Account/Register

          会员管理后台主页 /Identity/Account/Manage/index

          个人资料页 /Identity/Account/Manage/PersonalData

          个人资料删除 /Identity/Account/Manage/DeletePersonalData

          个人资料下载/Identity/Account/Manage/ DownloadPersonalData.cshtml

          分部页 _ManageNav.cshtml

      

      下面是 Account/Manage/Index.cshtml 页,已经加上自定义的二个用户字段信息,具体更新代码见官网

        下面是/Identity/Account/Manage/PersonalData.cshtml 页,已经可以下载和删除用户数据

       参考文献

        自定义用户数据

      

  • 相关阅读:
    Spring Boot 2.4版本前后的分组配置变化及对多环境配置结构的影响
    Spring Boot 2.4 对多环境配置的支持更改
    Spring Boot 的2020最后一击:2.4.1、2.3.7、2.2.12 发布
    苹果M1芯片各种不支持,但居然可以刷朋友圈!你会买单吗?
    老板居然让我在Java项目中“造假”
    Spring Cloud正式移除Hystrix、Zuul等Netflix OSS组件
    为了Java微信支付V3开发包,我找出了微信支付文档至少六个错误
    IdentityServer4系列 | 支持数据持久化
    IdentityServer4系列 | 混合模式
    Gitlab Runner的分布式缓存实战
  • 原文地址:https://www.cnblogs.com/MrHSR/p/10578369.html
Copyright © 2011-2022 走看看