本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity3.html

前言

上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身。

最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序在处理身份验证和授权有了很多的变化,多了比如手机端,平板等,所以那个时候为了适应这种变化就引入了ASP.NET Membership,但是随着时间的发展一些社交网站或者程序聚集了大量的用户,比如Facebook,Twitter,QQ等,这个时候用户希望能够使用他们在这些社交站点身份来登陆当前网站,这样可以免除注册这些琐碎而又必要的操作,用户也不必记住大量的账户密码。

又随着互联网的发展,越来越多的开发者不只是关注具体业务代码的编写,转变为开始关注应用程序代码的单元测试,这已经是开发者关注的核心。所以在2008年,ASP.NET 团队引入了 MVC 框架,这样来帮助开发者很方便的构建单元测试,同时开发者希望他们的 Membership 系统也能够做到这一点。

基于以上,ASP.NET Identity 应运而生。

Identity 要解决的问题

很多开发人员说他们不愿意使用Identity,自己实现要方便的多,OK,那么需求来了?以下就是我针对此次任务给你提出来的需求。

身份系统

  • 可以同时被所有的ASP.NET 框架使用(Web MVC,Web Forms,Web Api,SignalR)
  • 可以应用于构建 Web, 手机,存储,或者混合应用。

能够对用户资料(User Profile)很方便的扩展

  • 可以针对用户资料进行扩展。

持久化

  • 默认把用户信息存储在数据库中,可以支持使用EF进行持久化。(可以看到,EF 其实只是Identity的一个功能点而已
  • 可以控制数据库架构,更改表名或者主键的数据类型(int,string)
  • 可以使用不同的存储机制(如 NoSQL,DB2等)

单元测试

  • 使WEB 应用程序可以进行单元测试,可以针对ASP.NET Identity编写单元测试

角色机制

  • 提供角色机制,可以使用不同的角色来进行不同权限的限制,可以轻松的创建角色,向用户添加角色等。

要支持基于Claims

  • 需要支持基于 Claims 的身份验证机制,其中用户身份是一组Claims,一组Claims可以比角色拥有更强的表现力,而角色仅仅是一个bool值来表示是不是会员而已。

第三方社交登陆

  • 可以很方便的使用第三方登入,比如 Microsoft 账户,Facebook, Twitter,Google等,并且存储用户特定的数据。

封装为中间件

  • 基于中间件实现,不要对具体项目产生依赖
  • 基于 Authorzation 中间件实现,而不是使用 FormsAuthentication 来存储cookie。

NuGet包提供

  • 发布为 Nuget 包,这样可以容易的进行迭代和bug修复,可以灵活的提供给使用者。

以上,就是我提出来的需求,如果让你来封装这样一个用户身份认证组件,你会不是想到以上的这些功能点,那针对于这些功能点你又会怎么样来设计呢?

下面来看一下 Identity 怎么样设计的吧。

Getting Started

抽丝剥茧,我们先从入口看一下其使用方式。 首先我们打开 Startup.cs 文件,然后添加如下代码:

public class Startup
{ public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie";
options.Cookies.ApplicationCookie.CookieName = "Interop";
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
} public void Configure(IApplicationBuilder app)
{
// 使用了 CookieAuthentication 中间件做身份认证
app.UseIdentity();
}
}

在 ConfigureServices 中,先是注册了数据库上下文,然后又 services.AddIdentity() 我们看一下里面都注册了哪些服务呢?

public static IdentityBuilder AddIdentity<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// 这个就是被 Identity 使用的
services.AddAuthentication(options =>
{
// This is the Default value for ExternalCookieAuthenticationScheme
options.SignInScheme = new IdentityCookieOptions().ExternalCookieAuthenticationScheme;
}); // 注册 IHttpContextAccessor ,会用到
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); // Identity services
services.TryAddSingleton<IdentityMarkerService>();
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>(); // 错误描述信息
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>(); //身份当事人工厂
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>(); //三大对象
services.TryAddScoped<UserManager<TUser>, UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>, RoleManager<TRole>>(); if (setupAction != null)
{
services.Configure(setupAction);
} return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}

看了以上代码后,基本上知道了 Identity 他的设计的一个架构了,通过此结构我们也能够学习到我们自己封装一个中间件的时候,该怎么样来组织我们的代码结构,怎么样的利用 ASP.NET Core 给我们提供的依赖注入来更好的解耦,下面我们来看一下通过以上代码我们能够学到什么东西:

1、 在 public static IdentityBuilder AddIdentity<TUser, TRole>(this IServiceCollection services,    Action<IdentityOptions> setupAction) 这个扩展方法中,提供了一个参数 Action<IdentityOptions>,这个是干什么用的呢? 这个是我们在设计一个中间件的时候,有需要外部提供的参数,就会设计一个 Options 的类用来接受外部的参数,然后封装为一个Action委托的方式提供。在使用到的地方就可以以 IOption xxx 的形式注入进来使用了。

2、services.TryAddScoped<Interface,Implement>(),这个注册方式就是说,如果检测到DI容器里面已经有了当前要注册的Interface或者Service,就不会再次注册,没有才会注册进去。 那么为什么此处要这样用呢? 这是因为如果用户已经实现了此接口并且已经注册的容器当中的话,就使用用户注册的,而不是中间件自身的。用户就能很好的对中间件提供的功能进行自定义了,这就是OO中的多态性,这就是里氏替换原则。

3、如果你能理解第2条的话,那么你应该知道为什么会在服务中注册 错误描述信息 那个IdentityErrorDescriber 了吧,也能够解决你想提示账号密码错误,无奈Identity输出是英文问题的提示。

4、三大对象,这个是 Identity 的核心了,所以学习 Identity 的话,在看完博客 ASP.NET Core 之 Identity 入门()之后,学这三个对象就够了。

SignInManager: 主要处理注册登录相关业务逻辑。

UserManager: 处理用户相关添加删除,修改密码,添加删除角色等。

RoleManager:角色相关添加删除更新等。

有些同学可能很好奇,都没有依赖具体的数据库或者是EF,是怎么样做到的增删改查的呢?

这个时候,就需要几个 Store 接口派上用场了。以下是Identity中定义的Store接口:

  • IQueryableRoleStore
  • IQueryableUserStore
  • IRoleClaimStore
  • IRoleStore
  • IUserAuthenticationTokenStore
  • IUserClaimStore
  • IUserEmailStore
  • IUserLockoutStore
  • IUserLoginStore
  • IUserPasswordStore
  • IUserPhoneNumberStore
  • IUserRoleStore
  • IUserSecurityStampStore
  • IUserStore
  • IUserTwoFactorStore

有了这些接口之后,是不是豁然开朗了,原来 Identity 是通过这种方式实现的持久化机制,依赖抽象接口而不是依赖具体的细节实现,这就是面向对象中的依赖倒置原则呀。

Identity 和 EntityFramework

Identity 和 EntityFramework的关系,相信上个章节看懂了之后,就很容易明白了,对的,EF 只是针对于上述 Store 接口的实现,不信你看截图的源码:

Identity 打头的那些类文件都是定义的需要持久化的Entity对象,Store结尾的那些就是接口的实现啦。

第三方的 Identity 实现

除了 EF 是官方默认提供的持久化库之外,还有一些第三方的库,当然你也可以自己使用 ADO.NET 或者 Drapper 实现。

MangoDb 针对于 Identity 提供的实现: https://github.com/tugberkugurlu/AspNetCore.Identity.MongoDB

LinqToDB 针对于 Identity 提供的实现:https://github.com/linq2db/LinqToDB.Identity

总结

这篇博文写了蛮久的时间的,一方面是因为在构思怎么样的思路来让大家更好的理解,而不仅仅是使用。因为有太多的文章介绍Identity 的使用方式以及代码了,但是最后大家还是不会用。后来想到如果让别人想要理解你的库也好代码也好,让其知道诞生的背景是很重要的,因为这才是设计的初衷。另一方面是因为Connect() 2016 大会上,.NET Core 发布了 1.1 版本,除了把项目升级到1.1之外,也在学习1.1新的一些东西,以便更好给大家分享。

授人以鱼不如授人以渔, 一篇好的博文确实要花费作者更多的心血和时间。如果你觉得这篇博文对您有帮助,感谢您的【推荐】。

同时,ASP.NET Core 之 Identity 系列也结束了,感谢支持的朋友们。如果你对 .NET Core 感兴趣可以关注我,我会定期在博客分享关于 .NET Core 的学习心得。


本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-identity3.html 作者博客:Savorboard 欢迎转载,请在明显位置给出出处及链接

 
 

[转]ASP.NET Core 之 Identity 入门(三)的更多相关文章

  1. ASP.NET Core 之 Identity 入门(三)

    前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ...

  2. ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OW ...

  3. ASP.NET Core 之 Identity 入门(二)

    前言 在 上篇文章 中讲了关于 Identity 需要了解的单词以及相对应的几个知识点,并且知道了Identity处在整个登入流程中的位置,本篇主要是在 .NET 整个认证系统中比较重要的一个环节,就 ...

  4. [转]ASP.NET Core 之 Identity 入门(二)

    本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity2.html 前言 在 上篇文章 中讲了关于 Identity 需要了解的单词以 ...

  5. [转]ASP.NET Core 之 Identity 入门(一)

    本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity.html 前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里 ...

  6. ASP.NET Core 之 Identity 入门(转载)

    原文地址:https://www.cnblogs.com/gongap/p/9504562.html 前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库 ...

  7. Asp.Net Core之Identity应用(上篇)

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

  8. asp.net core使用identity+jwt保护你的webapi(三)——refresh token

    前言 上一篇已经介绍了identity的注册,登录,获取jwt token,本篇来完成refresh token. 开始 开始之前先说明一下为什么需要refresh token. 虽然jwt toke ...

  9. ASP.NET Core 1.0 入门——了解一个空项目

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

随机推荐

  1. Java aes加密C#解密的取巧方法

    摘要: 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦.Java的代码和C#的代码无法互通. Ja ...

  2. [无聊的事-连载之连开100个VS] 折腾你的骚机吧,骚年们!!!

    [无聊的事-连载之连开100个VS] 折腾你的骚机吧,骚年们!!! 只有8G内存的,用这个:打开你的CMD命令提示符如果只装了Visual Studio 2010,用这条命令,打开50个VSfor / ...

  3. IoC原理-使用反射/Emit来实现一个最简单的IoC容器

    从Unity到Spring.Net,到Ninject,几年来陆陆续续用过几个IoC框架.虽然会用,但也没有一直仔细的研究过IoC实现的过程.最近花了点时间,下了Ninject的源码,研究了一番,颇有收 ...

  4. IIS实现反向代理

    http://www.cnblogs.com/dreamer-fish/p/3911953.html C#实现: C#写的一个反向代理,可以缓存 https://www.oschina.net/cod ...

  5. 工厂模式 - Factory

    简单工厂模式 SimpleFactory Pattern,将一个具体类的实例化交给一个静态工厂方法来执行. 特点: 增加功能需要修改工厂类,扩展性较差: 参考: 设计模式学习笔记 - 简单工厂模式: ...

  6. 初识Mybatis框架,实现增删改查等操作(动态拼接和动态修改)

    此第一次接触Mybatis框架确实是有点不适应,特别是刚从Hibernate框架转转型过来,那么为什么要使用Mybatis框架,Mybatis框架和Hibernate框架又有什么异同呢? 这个问题在我 ...

  7. ZHA profile与ZLL profile的一个例子

    ZHA Coordinator 如何控制ZLL Light/Philips Hue Light 缩写: ZHA: ZigBee Home Automation profile ZLL:  ZigBee ...

  8. 25M时钟的梁祝演奏

    module liangzhu(clk_50M,rst,speaker); input clk_50M,rst; output speaker; reg speaker; //分频计数器paramet ...

  9. PHP学习资料下载

    yii2教程以及手册 https://yunpan.cn/ckkhbccyqGVYg (提取码:09b8) mysql学习 链接: http://pan.baidu.com/s/1kUTC8tT 密码 ...

  10. 基于 Eclipse 的 MapReduce 开发环境搭建

    文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6055850.html 上周末本来要写这篇的,结果没想到上周末自己环境都没有搭起来,运行起 ...