英文原文:http://tech.trailmax.info/2014/08/aspnet-identity-and-owin-who-is-who/

最近我发现Stackoverflow上有一个非常好的问题.提问者问:为什么在调用AuthenticationManager.SignIn后,claim仍然可以被添加到Identity并持久化到cookie里.

示例代码如下所示:

ClaimsIdentity identity = UserManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie );

var claim1 = new Claim(ClaimTypes.Country, "Arctica");
identity.AddClaim(claim1); AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, identity ); var claim2 = new Claim(ClaimTypes.Country, "Antartica");
identity.AddClaim(claim2);

是的,为什么claim2在cookie已经设置完成后还可用.

在深入研究后,我发现AspNet Identity框架不设置cookie,而OWIN会设置,OWIN是Katana开源项目的一部分.有源码可用是一件好事--你可以发现为什么事情有或没有按你预期的方式工作.

在这个案例里,我花了一些时间探索Katana项目和 AuthenticationManager 工作方式.结果证明SignIn方法不设置cookie.它把Identity对象保存在内存里,直到设置响应cookies的时刻到来,然后claims被转化为一个cookie,所有的事情就这样魔法般地工作着 -)

这又引发了另一个问题.现下Identity没有开源的代码,所以OWIN在Identity中扮演什么角色,Claims又是如何工作的?

结果证明Identity框架只处理user持久化,密码哈希,验证密码是否正确,发送密码重置邮件,等等.但是Identity实际上不验证users或创建cookies.而Cookies是被OWIN处理的.

看一下登录的代码:

public async Task SignInAsync(Microsoft.Owin.Security.IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent)
{
authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); ClaimsIdentity identity = await UserManager.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie); authenticationManager.SignIn(new Microsoft.Owin.Security.AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

Identity只创建ClaimsIdentity(学习网站 ReferenceSource ),而ClaimsIdentity是.Net framework的一部分,而不是来自于互联网的nuget包.然后这个ClaimsIdentity被传给拥有一个设置cookies回调的OWIN的AuthenticationManager,而AuthenticationManager拥有一个在写响应头时设置cookies的回调.

到目前为止都很好,已有三部分:Identity框架创建一个ClaimsIdentity,OWIN根据这个ClaimsIdentity创建一个cookie,和.Net framework掌控ClaimsIdentity的类.

当在你的类中要访问ClaimsPrincipal.Current时,你只用到.Net framework,不需要用到其它类库,这是非常方便的!

默认的Claims

Identity框架为你做了一件很漂亮的事,默认情况下当你登录时,它为一个principal添加了一些claims,如下所示:

  • User.Id:类型为“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier” 或ClaimTypes.NameIdentifier.
  • Username:类型为“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name” 或ClaimTypes.Name.
  • "ASP.NET Identity":保存为“http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider“.这在你使用OpenId做验证时非常有用.不过如果只是使用数据库存储users时没什么用.点击查看更多信息.
  • 包含user的安全邮戳的Guid,在Claim中持久化类型为“AspNet.Identity.SecurityStamp“.安全邮戳是user状态的一个主要快照,如果验证的密码/方法,email,等等发生变化,安全邮戳就会发生变化,这允许你通过改变证书实现"在任何地方登出".从Kung的回答中获取更多有关安全邮戳的信息.
  • 最有用的claims是role.所有分配给user的role被保存成ClaimTypes.Role或“http://schemas.microsoft.com/ws/2008/06/identity/claims/role“.所以下次你需要检查当前user的roles,检查这个claims,不会到数据库中查找,这样非常快.实际上,如果你调用ClaimsPrincipal的.IsInRole("RoleName"),框架会进入claims并检查用户是否分配了这个指定值的Role.

你可以在.Net Reference 网站查看这些claim类型,这个列表不是完整的,你可以创建你自己的claim类型--就是一个string.

如果你想添加你自己的owin claim类型,我建议你使用自己的符号,例如:“MyAppplication:GroupId” ,并保持所有的claim类型作为常量在一个类中:

public class MyApplicationClaimTypes
{
public string const GroupId = "MyAppplication:GroupId";
public string const PersonId = "MyAppplication:PersonId";
// other claim types
}

这种方式,你总是可以找到claims,并不会与框架中的claim类型冲突,除非你的claims与框架中的claims类型完全一致,例如:ClaimTypes.Email.

添加默认的claims

我总是在user登录里,添加user的email到claims列表中,就如最前面示例里的claim1和claim2:

public async Task SignInAsync(IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent)
{
authenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.ApplicationCookie); var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie); // using default claim type from the framework
identity.AddClaim(new Claim(ClaimTypes.Email, applicationUser.Email)); authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

你可以在这里为所有user添加默认的claims,但有一个IClaimsIdentityFactory类(赋给UserManager),只有一个方法:

public interface IClaimsIdentityFactory<TUser, TKey> where TUser : class, IUser<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Create a ClaimsIdentity from an user using a UserManager
/// </summary>
Task<ClaimsIdentity> CreateAsync(UserManager<TUser, TKey> manager, TUser user, string authenticationType);
}

AspNet Identity的默认实现是:创建ClaimsIdentity,添加如上所述的默认claims,为user在数据库中存储IdentityUserClaims类型的claims.你可以重写这个实现,并插入你自己的逻辑/claims:

public class MyClaimsIdentityFactory : ClaimsIdentityFactory<ApplicationUser, string>
{
public override async Task<ClaimsIdentity> CreateAsync(UserManager<ApplicationUser, string> userManager, ApplicationUser user, string authenticationType)
{
var claimsIdentity = await base.CreateAsync(userManager, user, authenticationType); claimsIdentity.AddClaim(new Claim("MyApplication:GroupId", "")); return claimsIdentity;
}
}

然后在赋给UserManger:

public UserManager(MyDbContext dbContext)
: base(new UserStore<ApplicationUser>(dbContext))
{
// other configurations // Alternatively you can have DI container to provide this class for better application flexebility
this.ClaimsIdentityFactory = new MyClaimsIdentityFactory();
}

AspNet Identity 和 Owin 谁是谁的更多相关文章

  1. 译:Asp.Net Identity与Owin,到底谁是谁?

    送给正在学习Asp.Net Identity的你 :-) 原文出自 trailmax 的博客AspNet Identity and Owin. Who is who. Recently I have ...

  2. 【译】Asp.Net Identity与Owin,到底谁是谁?

    送给正在学习Asp.Net Identity的你 :-) 原文出自 trailmax 的博客AspNet Identity and Owin. Who is who. Recently I have ...

  3. Microsoft.AspNet.Identity 自定义使用现有的表—登录实现

    Microsoft.AspNet.Identity是微软新引入的一种membership框架,也是微软Owin标准的一个实现.Microsoft.AspNet.Identity.EntityFrame ...

  4. 从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构

    Microsoft.AspNet.Identity简介 Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的mem ...

  5. AspNet Identity and IoC Container Registration

    https://github.com/trailmax/IoCIdentitySample TL;DR: Registration code for Autofac, for SimpleInject ...

  6. [.Net MVC] 用户角色权限管理_使用CLK.AspNet.Identity

    项目:后台管理平台 意义:一个完整的管理平台需要提供用户注册.登录等功能,以及认证和授权功能. 一.为何使用CLK.AspNet.Identity 首先简要说明所采取的权限控制方式.这里采用了基于角色 ...

  7. ASP.NET没有魔法——Identity与Owin

    上篇文章介绍了如何在ASP.NET MVC项目中引入Identity组件来实现用户注册.登录及身份验证功能,并且也提到了Identity是集成到Owin中的,本章就来介绍一下什么是Owin以及如何使用 ...

  8. Microsoft.AspNet.Identity 的简单使用

    要完成一个简单的注册,登陆,至少需要实现Identity中的3个接口 IUser IUserStore<TUser> : IDisposable where TUser : IUser I ...

  9. Microsoft.AspNet.Identity 自定义使用现有的表—登录实现,aspnet.identity

    Microsoft.AspNet.Identity是微软新引入的一种membership框架,也是微软Owin标准的一个实现.Microsoft.AspNet.Identity.EntityFrame ...

随机推荐

  1. TCP协议和UDP协议的区别

    1. TCP协议面向连接. UDP协议面向非连接 (有无链接)2. TCP协议传输速度慢. UDP协议传输速度快 (传输速度)3. TCP协议保证数据顺序. UDP协议不保证 (数据的有序性. 在IP ...

  2. js函数——setinterval和setTimeout

    1.window.setTimeout方法 该方法可以延时执行一个函数,例如: <script language="JavaScript" type="text/j ...

  3. STM32 对内部FLASH读写接口函数(转)

    源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...

  4. iOS开发——An App ID with identifier "*****" is not avaliable

    Error: An App ID with identifier "*****" is not avaliable. Please enter a different string ...

  5. CSS实现导航条Tab切换的三种方法

    前面的话   导航条Tab在页面中非常常见,本文说详细介绍CSS实现导航条Tab的三种方法 布局   根据上图所示,先规定几个定义,上图的模块整体叫做导航,由导航标题和导航内容组成.要实现上图所示的布 ...

  6. limesurvey设置短调查问卷url

    If you want to use fancy URLs and so not have /index.php in every URL please edit /application/confi ...

  7. 添加Pods依赖

    1. 添加所需文件 1.1. 添加 .podspec 文件 1.1.1.  创建 必须文件 使用命令 pod spec create name.podspec 或者直接拷贝一份 1.1.2.  添加内 ...

  8. 2.12. 后端 SQL 的可见性(Core Data 应用程序实践指南)

    上一节已经插入了数据,非常好.但是,我得更进一步.要知道里面究竟发生了什么,持久化存储区的数据有什么变化,生成了哪些查询语句.每次运行程序时,是否重复插入了对象. 有一个调试选项可以提供足够的信息,开 ...

  9. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  10. NodeMCU之旅(二):断线自动重连,闪烁连接状态

    事件监听器 NodeMCU采用了事件响应的方式.也就是说,只需为事件设置一个回调函数,当事件发生时,回调函数就会被调用. 注册事件监听器 wif.sta.eventMonReg() 开始监听 wifi ...