上一篇:AspNetCore.Identity详解1——入门使用

打开数据库,可以看到使用EF自动生成的表结构如下:

重点关注AspNetUsers表,打开数据库里的表可以知道目前也只用到了这张表。然后下载asp.net core开源代码 。在我们创建的项目里并没有/Identity/Account/Register 页面,可以猜测登录注册的页面必然封装在Microsoft.AspNetCore.Identity 里面。

<form asp-controller="Account" asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
    略......
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <button type="submit" class="btn btn-default">Register</button>
        </div>
    </div>
</form>

找到Account/Register 的post方法:

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
                var result = await _userManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
                    // Send an email with this link
                    //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
                    //await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
                    //    "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    _logger.LogInformation(, "User created a new account with password.");
                    return RedirectToLocal(returnUrl);
                }
                AddErrors(result);
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

这一行代码会帮我们完成注册任务

var result = await _userManager.CreateAsync(user, model.Password);

查看user 实体的定义

    public class ApplicationUser : IdentityUser
    {
    }

    public class IdentityUser : IdentityUser<string>
    {

        public IdentityUser()
        {
            Id = Guid.NewGuid().ToString();
            SecurityStamp = Guid.NewGuid().ToString();
        }

        public IdentityUser(string userName) : this()
        {
            UserName = userName;
        }
    }

   public class IdentityUser<TKey> where TKey : IEquatable<TKey>
    {

        public IdentityUser() { }

        public IdentityUser(string userName) : this()
        {
            UserName = userName;
        }

        [PersonalData]
        public virtual TKey Id { get; set; }

        [ProtectedPersonalData]
        public virtual string UserName { get; set; }

        public virtual string NormalizedUserName { get; set; }

        [ProtectedPersonalData]
        public virtual string Email { get; set; }

        public virtual string NormalizedEmail { get; set; }

        [PersonalData]
        public virtual bool EmailConfirmed { get; set; }

        public virtual string PasswordHash { get; set; }

        public virtual string SecurityStamp { get; set; }

        public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

        [ProtectedPersonalData]
        public virtual string PhoneNumber { get; set; }

        [PersonalData]
        public virtual bool PhoneNumberConfirmed { get; set; }

        [PersonalData]
        public virtual bool TwoFactorEnabled { get; set; }

        public virtual DateTimeOffset? LockoutEnd { get; set; }

        public virtual bool LockoutEnabled { get; set; }

        public virtual int AccessFailedCount { get; set; }

        public override string ToString()
            => UserName;
    }

打开CreateAsync方法,可以看到经过三步完成用户注册

        public virtual async Task<IdentityResult> CreateAsync(TUser user, string password)
        {
            ThrowIfDisposed();

            var passwordStore = GetPasswordStore();
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            var result = await UpdatePasswordHash(passwordStore, user, password);
            if (!result.Succeeded)
            {
                return result;
            }

            return await CreateAsync(user);
        }

逐个查看注释1,2,3的方法

       private IUserPasswordStore<TUser> GetPasswordStore()
        {
            var cast = Store as IUserPasswordStore<TUser>;
            if (cast == null)
            {
                throw new NotSupportedException(Resources.StoreNotIUserPasswordStore);
            }
            return cast;
        }

GetPasswordStore()方法会返回IUserPasswordStore<TUser>接口,Store 这个变量是什么呢?是IUserStore<TUser>,让人困惑的是IUserPasswordStore<TUser>继承了IUserStore<TUser>,

为什么Store可以转换为自己的子类呢?找到UserStoreBase类,看到它继承了IUserPasswordStore接口,由此可以猜测Store是UserStoreBase的实例。

// TUser是ApplicationUser
//protected internal IUserStore<ApplicationUser> Store { get; set; }
protected internal IUserStore<TUser> Store { get; set; }

第二步,完成了对密码的加密工作,同时更新了用户的安全戳(就是一个随机生成的字符串)

        private async Task<IdentityResult> UpdatePasswordHash(IUserPasswordStore<TUser> passwordStore,
            TUser user, string newPassword, bool validatePassword = true)
        {
            if (validatePassword)
            {
                var validate = await ValidatePasswordAsync(user, newPassword);
                if (!validate.Succeeded)
                {
                    return validate;
                }
            }
            var hash = newPassword != null ? PasswordHasher.HashPassword(user, newPassword) : null;
            await passwordStore.SetPasswordHashAsync(user, hash, CancellationToken);
            await UpdateSecurityStampInternal(user);
            return IdentityResult.Success;
        }

第三步:完成对用户的最终创建

       public virtual async Task<IdentityResult> CreateAsync(TUser user)
        {
            ThrowIfDisposed();
            await UpdateSecurityStampInternal(user);
            var result = await ValidateUserAsync(user);
            if (!result.Succeeded)
            {
                return result;
            }
            if (Options.Lockout.AllowedForNewUsers && SupportsUserLockout)
            {
                await GetUserLockoutStore().SetLockoutEnabledAsync(user, true, CancellationToken);
            }
            await UpdateNormalizedUserNameAsync(user);
            await UpdateNormalizedEmailAsync(user);

            return await Store.CreateAsync(user, CancellationToken);
        }

找到UserOnlyStore类,这里面有最后一步向数据库插入用户的操作。

整个过程很绕,在理清逻辑的过程中很容易迷失。如果想要避免迷失,一定要牢记我们只是想看看注册用户这一步是怎样完成的,千万不要关心与之无关的代码。

AspNetCore.Identity详解2——注册用户的更多相关文章

  1. AspNetCore.Identity详解1——入门使用

    今年在面试的时候被问到单点登录的知识,当时支支吾吾不知该如何作答,于是面试失败.回到住所便开始上网查找资料,但苦于难于找到详尽的demo,总是无法入门.又由于我正在学习了解asp.net core,里 ...

  2. CEPH-2:rbd功能详解及普通用户应用ceph集群

    ceph集群rbd使用详解 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍rbd存储功能如何灵活的使用,集群背景: $ ceph -s cluster: id: 53717 ...

  3. ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解 (转载)

    “传导体” HttpContext 要理解 HttpContext 是干嘛的,首先,看图 图一 内网访问程序 图二 反向代理访问程序 ASP.NET Core 程序中,Kestrel 是一个基于 li ...

  4. ASP.NET Identity详解

      Asp.Net Identiy是ASP.NET身份验证机制. 如何构建安全的Web应用? 我们先来思考一个问题:如何构建安全的WEB应用? 一直以来,这都是比较热门的话题.不幸的是,目前还没有一种 ...

  5. ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解

    笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 ASP.NET Core MVC 基础后,开始学习 ASP.NET Core 的运行原理.发现应用程序有一个非常主要的 “传导体” ...

  6. 详解Windows注册表分析取证

    大多数都知道windows系统中有个叫注册表的东西,但却很少有人会去深入的了解它的作用以及如何对它进行操作.然而对于计算机取证人员来说注册表无疑是块巨大的宝藏.通过注册表取证人员能分析出系统发生了什么 ...

  7. 详解MySQL的用户密码过期功能

    这篇文章主要为大家详细介绍了MySQL的用户密码过期功能的相关资料,需要的朋友可以参考下   Payment Card Industry,即支付卡行业,PCI行业表示借记卡.信用卡.预付卡.电子钱包. ...

  8. 详解Oracle创建用户权限全过程

    本文将介绍的是通过创建一张表,进而实现Oracle创建用户权限的过程.以下这些代码主要也就是为实现Oracle创建用户权限而编写,希望能对大家有所帮助. 注意:每条语语分开执行,结尾必须用分号; // ...

  9. 详解管理root用户权限的sudo服务程序

    在你想要使用超级权限临时运行一条命令时,sudo 命令非常方便,但是当它不能如你期望的工作时,你也会遇到一些麻烦.比如说你想在某些日志文件结尾添加一些重要的信息,你可能会尝试这样做: $ echo & ...

随机推荐

  1. 21个极大提高开发效率的VS Code快捷键

    摘要: 高效使用VS Code! 作者:前端小智 原文:21 个VSCode 快捷键,让代码更快,更有趣 Fundebug经授权转载,版权归原作者所有. 注意:自己尝试的时候,Mac(17, pro) ...

  2. python 环境配置的导入与导出

    Python——配置环境的导出与导入   导出Python环境安装包[root@bogon ~]# pip freeze > packages.txt这将会创建一个 packages.txt文件 ...

  3. 3. gn入门

    Chromium是用gn和ninja进行编译的,即gn把.gn文件转换成.ninja文件,然后ninja根据.ninja文件将源码生成目标程序.gn和ninja的关系就与cmake和make的关系差不 ...

  4. flask POOL,websocket握手

    一.POOL Pool就是为了多线程访问数据库,减少数据库压力 回顾pymysql import pymysql #建立连接 mysql_conn = pymysql.connect(host=&qu ...

  5. 201871010105-曹玉中《面向对象程序设计(java)》第十五周学习总结

    201871010105-曹玉中<面向对象程序设计(java)>第十五周学习总结 项目 内容 这个作业属于哪个过程 https://www.cnblogs.com/nwnu-daizh/ ...

  6. 201871010135 张玉晶《面向对象程序设计(java)》第6-7周学习总结

    201871010135 张玉晶<面向对象程序设计(java)>第6-7周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  7. springboot常见问题

    什么是 Spring Boot? 为什么要用 Spring Boot? Spring Boot 的核心配置文件有哪几个?它们的区别是什么? Spring Boot 的配置文件有哪几种格式?它们有什么区 ...

  8. Linux系统下root密码遗忘等系统故障的修复方法 - 运维总结

    IDC机房有一台centos系统的服务器,由于这台服务器的系统装了好长时间,且root密码中间更新过几次,后面去机房现场维护时,登陆密码遗忘了,悲催啊~没办法,只能开机进入“单用户模式”进行密码重置了 ...

  9. Dockerfile解析(八)

    一.Dockerfile是什么 Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本. 1. 构建的步骤 运行容器:docker run 构建新的镜像:docker ...

  10. Mysql 视图&事务&触发器

    参考资料 一.视图 视图的含义: 视图是一个虚拟表,是从数据库中一个或者多个表中导出来的表. 1.创建视图 #语法:CREATE VIEW 视图名称 AS SQL语句 create view teac ...