一、前言

在前面的篇章介绍中,简单介绍了IdentityServer4持久化存储机制相关配置和操作数据,实现了数据迁移,但是未对用户实现持久化操作说明。在总结中我们也提到了,

因为IdentityServer4本就支持了接入其他认证方式,所以自己根据需要进行合理扩展的,比如我们可以使用 Asp.Net Core 自带的 Identity 身份认证机制来实现扩展,实现用户数据持久化操作。

当然了,本篇暂时抛开IdentityServer4这个话题,而是单独认识一下Asp.Net Core 自带的 Identity 身份认证机制是什么样的?

因此,本篇主要介绍的是将ASP.NET Core Identity 实战应用。

二、初识

ASP.NET Core Identity是用于构建ASP.NET Core Web应用程序的身份认证系统,包括用户数据,用户身份以及注册登录信息数据存储,可以让您的应用拥有登录功能以及持续化存储登录用户相关数据。

ASP.NET Core Identity(下文简称Identity)可以简单的用户管理系统,但是却是一个功能强大的系统,包含用户管理的方方面面,主要包括:

  1. 用户数据存储(使用任意你喜欢的关系型数据库,从sqllite到mysql、sqlserver等等,由Entity Framwork 支持)
  2. 登陆、注册外加身份认证(基于cookie的身份认证,如果你使用Vs那么还可以生成用于注册登录的用户界面及处理代码)
  3. 角色管理
  4. 基于声明的认证模式

具体对于Identity的理解可以参考Asp.Net Core之Identity入门

接下来我们主要是实践应用一下,理解Identity

三、实践

3.1 创建项目

基于vs2019, .net core3.1创建asp.net core web 应用程序。

3.1.1 流程:

1.选择“文件” > “新建” > “项目”。
2.选择“ASP.NET Core Web应用程序”。 将项目命名WebIdentityDemoV3.0具有项目下载相同的命名空间。 单击 “确定”。
3.选择 ASP.NET Core Web MVC应用程序,然后选择更改身份验证。
4.选择单个用户帐户然后单击确定。

生成的项目 ASP.NET Core Identity 以类库形式Razor提供。

3.1.2 目录结构:

3.1.3 迁移数据

找到appsettings.json文件, ConnectionStrings的数据库连接字符串,默认是连接本地的数据库,当然了,你也可以改成你指定的数据库地址。

"ConnectionStrings": {
"DefaultConnection": "Data Source=.;initial catalog=IdentityV3;user id=sa;password=123456;"
},

基于生成的迁移代码,同步到数据库

PM> Update-Database

到了这里,我们基本完成了Identity项目的搭建了,可以就此运行登录注册。

3.1.4 效果如下:

可是回到生成的目录结构看来,却发现没有Identity用户相关的model,cshtml等文件。这是为何呢?

其实这些相关文件已由内置Razor类库提供。所以生成的代码目录没有。

但实际开发中,我们需要生成相应的源代码,以便根据开发需求拓展更改代码和更改行为。所以可以根据net core为我们提供的基架标识(Scaffold Identiy)生成需要重写的文件。

3.2 基架标识

在ASP.NET Core 2.1 及更高版本提供了ASP.NET Core Identity作为Razor 类库。 包含Identity的应用程序可以应用基架,来有选择地添加包含在Identity Razor 类库 (RCL) 的源代码。

3.2.1 流程:

1.从对应的项目中,右键单击该项目 >添加 > 新基架项。

2.从左窗格添加基架对话框中,选择标识 > 添加。

3.在中添加 标识添加对话框中,选择所需的选项。

下面使用现有的数据上下文,选择所有文件,以便后面重写,如下所示。

这里示例 所以我选择只添加 RegisterLoginLogOutRegisterConfirmation 文件

3.2.2 效果:

生成后,目录新增变化:

可以发现,在Areas目录下,生成了Razor Page文件,需要注意的是这不是MVC视图控制器。

刚刚介绍说了,这是因为在ASP.NET Core 2.1及更高版本提供了ASP.NET Core Identity作为Razor 类库,不再是之前的2.0的类库, 因为是基于Razor Page的,

所以找不到原来在2.0版本下的Controllers(如Account等控制器)

这个时候如果你想该页面或者的代码,就需要基于基架重写文件到你的项目中后,再做具体修改。

但是如果你又想实现MVC这种视图控制器的话,你可以基于Razor Page中的,重写生成对应的控制器及业务逻辑,来实现视图控制器这种方式。

四、区别

2.0 版本

看到有人问:.net core mvc模板选个人身份验证后 Identity区域下Account控制器在哪里?

其实这是因为在ASP.NET Core 2.1及更高版本提供了ASP.NET Core Identity作为Razor 类库,不再是之前的2.0的类库, 因为是基于Razor Page的,所以找不到原来在2.0版本下的Controllers(如Account等控制器)

但是如果你又想实现MVC这种视图控制器的话,你可以基于Razor Page中的,重写生成对应的控制器及业务逻辑,来实现视图控制器这种方式。当然了,你也可以利用2.0版本的项目进行参考重写你的业务。

4.1 创建项目

基于vs2019, .net core2.0 创建asp.net core web 应用程序。

4.1.1 流程:

1.选择“文件” > “新建” > “项目”。
2.选择“ASP.NET Core Web应用程序”。 将项目命名WebIdentityDemoV2.0具有项目下载相同的命名空间。 单击 “确定”。
3.选择 ASP.NET Core Web MVC应用程序,然后选择更改身份验证。
4.选择单个用户帐户然后单击确定。

生成的项目 ASP.NET Core Identity 以类库形式Razor提供。

4.1.2 目录结构:

可以发现, 在我们选择个人身份认证的时候 Identity被自动添加到项目中,并且生成了

  • 账户控制器AccountController 注册和登陆相关的代码都在这里)
  • 登陆注册页面(还有其它的 如:确认邮件、访问受限等等)
  • 管理控制器(ManageController 这是给注册用户用的,主要有两个功能,改密码和双因子验证)

已经出现了MVC这种视图控制器,也可以找到对应的控制器方法了。这也是相比于升级到2.1及更高版本的不同之处。

在2.0版本中的MVC视图控制器模式而升级到2.1及更高版本后,直接采用了Razor类库,改成了将控制器写到了cshtml文件上了。

4.1.3 迁移数据:

找到appsettings.json文件, ConnectionStrings的数据库连接字符串,默认是连接本地的数据库,当然了,你也可以改成你指定的数据库地址。

"ConnectionStrings": {
"DefaultConnection": "Data Source=.;initial catalog=IdentityV2;user id=sa;password=123456;"
},

基于生成的迁移代码,同步到数据库

PM> Update-Database

到了这里,我们基本完成了2.0 版本的Identity项目的搭建了,可以就此运行登录注册了。

到了这里, 我们也就体验了Asp.Net Core2.0以及在升级到2.1及更高版本后发生的变化了。

五、扩展

5.1 配置问题

5.1.1 默认配置:

如下是代码Identity的默认选项配置,服务通过依赖关系注入提供应用程序。

public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
//这里需要注意的是 options.SignIn.RequireConfirmedAccount 设置项,缺省设置为true,
//这种情况下,新注册的用户需要进行确认才能完成注册,如果没有安装邮件系统,这个步骤无法完成,所以这里改为false。
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}

通过调用启用 UseAuthenticationUseAuthentication 将身份验证 中间件 添加到请求管道。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}

除了上面的默认配置选项以后,你也可以根据自身的业务要求,比如有些想要对用户名做限制,有些需要在密码做限制等等。

典型模式是调用所有 Add{Service} 方法,然后调用所有 services.Configure{Service} 方法。

5.1.2 自定义配置:

a. 配置用户名:

services.AddDefaultIdentity<IdentityUser>(options =>
{
options.User = new UserOptions
{
RequireUniqueEmail = true, //要求Email唯一
AllowedUserNameCharacters = "abcdefgABCDEFG" //允许的用户名字符,默认是 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+
};
});

不支持正则表达式,如果需要支持汉字,可能需要添加很多汉字才行。。

b. 配置密码:

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.Password = new PasswordOptions
{
RequireDigit = true, //要求有数字介于0-9 之间, 默认true
RequiredLength = 8, //要求密码最小长度, 默认是 6 个字符
RequireLowercase = true, //要求小写字母, 默认true
RequireNonAlphanumeric = true, //要求特殊字符, 默认true
RequiredUniqueChars = 3, //要求需要密码中的非重复字符数, 默认1
RequireUppercase = true //要求大写字母 ,默认true
};
})

c. 锁定账户

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.Lockout = new LockoutOptions
{
AllowedForNewUsers = true, // 新用户锁定账户, 默认true
DefaultLockoutTimeSpan = TimeSpan.FromHours(1), //锁定时长,默认是 5 分钟
MaxFailedAccessAttempts = 3 //登录错误最大尝试次数,默认 5 次
};
})

d. 数据库存储

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.Stores = new StoreOptions
{
MaxLengthForKeys = 128, // 主键的最大长度
ProtectPersonalData = true //保护用户数据,要求实现 IProtectedUserStore 接口
};
})

如果不设置,主键则是 max 的字符串长度。

e. 令牌配置

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.Tokens = new TokenOptions
{
AuthenticatorTokenProvider = "MyAuthenticatorTokenProvider", //用于使用验证器验证双重登录的。
ChangeEmailTokenProvider = "MyChangeEmailTokenProvider", //用于生成电子邮件更改确认电子邮件中使用的令牌的。
ChangePhoneNumberTokenProvider = "MyChangePhoneNumberTokenProvider", //用于生成更改电话号码时使用的令牌的。
EmailConfirmationTokenProvider = "MyEmailConfirmationTokenProvider", //用于生成帐户确认电子邮件中使用的令牌的令牌提供程序。
PasswordResetTokenProvider = "MyPasswordResetTokenProvider", //用于生成密码重置电子邮件中使用的令牌
ProviderMap = new Dictionary<string, TokenProviderDescriptor>(), //用作提供程序名称的密钥构造 用户令牌提供程序 。
AuthenticatorIssuer = "Identity", //认证的消费者
};
})

如何生成令牌,然后用什么方式将令牌发给用户,请求用户验证。

f. 声明配置

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.ClaimsIdentity = new ClaimsIdentityOptions
{
RoleClaimType = "IdentityRole", // 用于角色声明的声明类型。
UserIdClaimType = "IdentityId", // 用于用户标识符声明的声明类型。
SecurityStampClaimType = "SecurityStamp", //用于安全戳声明的声明类型。
UserNameClaimType = "IdentityName" //用于用户名声明的声明类型。
};
})

g. 登录配置:

services.AddDefaultIdentity<IdentityUser>(options=>
{
options.SignIn = new SignInOptions
{
RequireConfirmedEmail = true, //要求激活邮箱., 默认false
RequireConfirmedPhoneNumber = true //要求激活手机号才能登录,默认false
};
})

在登录的时候,如果手机号或邮箱没有激活/确认,则无法登录。

h. Cookie 设置:

services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.Cookie.Name = "YourAppCookieName";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.LoginPath = "/Identity/Account/Login";
// ReturnUrlParameter requires
//using Microsoft.AspNetCore.Authentication.Cookies;
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.SlidingExpiration = true;
});

在中配置应用 cookie 程序 Startup.ConfigureServices 。 ConfigureApplication Cookie调用或 后必须调用 AddIdentity``AddDefaultIdentity

i. Password Hasher 设置:

services.Configure<PasswordHasherOptions>(option =>
{
option.IterationCount = 12000; //使用 PBKDF2 对密码进行哈希处理时使用的迭代次数。
});

PasswordHasherOptions 获取和设置用于密码哈希的选项。

j. 全局要求对所有用户进行身份验证

   services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});

六、总结

  1. 本篇简单介绍了 Asp.Net Core 自带的 Identity,一个负责对用户的身份进行认证的组件库,同时进行了相关的实战应用体验。
  2. 后续会对Identity自定义用户以及表结构说明。
  3. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。
  4. 项目地址

七、附加

Asp.Net Core简介Identity

配置 ASP.NET Core Identity

Asp.Net Core之Identity入门

最新文章

  1. 【BZOJ2318】Spoj4060 game with probability Problem 概率
  2. TopCoder SRM 596 DIV 1 250
  3. MySQL 如何只导出 指定的表 的表结构和数据 ( 转 )
  4. 破解 Splish
  5. WC2015 滚粗记
  6. QML学习心得
  7. Javascript 【JSON对象】
  8. 使用Windows2003创建AD服务器 - 进阶者系列 - 学习者系列文章
  9. Delphi TRect函数例子
  10. stickUp.js:98 Uncaught ReferenceError: vartop is not defined at HTMLDocument.&lt;anonymous&gt; (stickUp.js:98)
  11. thymeleaf手动映射根路径映射
  12. swift 学习- 19 -- 可选链式调用
  13. linux 下动态链接实现原理
  14. Socket网络编程--聊天程序(2)
  15. 精通Oracle的关键是……(Ask Tom上最经常被问到的问题)(转)
  16. akka共享内存
  17. CF558E A Simple Task
  18. 使用nginx做反代时遇到413 Request Entity Too Large的解决方法
  19. CVE-2011-0104 Microsoft Office Excel缓冲区溢出漏洞 分析
  20. 更改nginx站点根文件夹

热门文章

  1. strtok:This function or variable may be unsafe.
  2. shell 和python 实现ftp文件上传或者下载
  3. Python——模块&包&异常
  4. 我完成了10000小时开发3D引擎
  5. 矩池云 | 搭建浅层神经网络&quot;Hello world&quot;
  6. vivo鲁班RocketMQ平台的消息灰度方案
  7. laravel7 图片上传及视图显示
  8. 写给开发人员的实用密码学(七)—— 非对称密钥加密算法 RSA/ECC
  9. 6月11日 python复习 mysql
  10. 程序流程控制1 if 分支机构