var user = UserManager.Find(...);
ClaimsIdentity identity = UserManager.CreateIdentity(
user, DefaultAuthenticationTypes.ApplicationCookie );
var claim1 = new Claim(
ClaimType = ClaimTypes.Country, ClaimValue = "Arctica", UserId = user.Id );
identity.AddClaim(claim1);
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = true }, identity );
var claim2 = new Claim(
ClaimType = ClaimTypes.Country, ClaimValue = "Antartica", UserId = user.Id );
identity.AddClaim(claim2);
claim1
和claim2
仅在用户登录时跨请求保留ClaimsIdentity
。换句话说,当用户通过调用SignOut()
注销时,这两个声明也会被删除,因此下次该用户登录时,它不再是这两个声明的成员(我假设这两个声明不再存在(
claim2
在请求中持久化的事实(即使将身份验证cookie添加到用户时已经创建了身份验证cookie claim2
(表明声明不会通过身份验证cookie在请求中持久化,而是通过其他方式持久化。
那么,如何在请求中保留声明呢?
编辑:
1( 据我所知,IdentityUserClaim
类型的声明永远不会保留在 cookie 中?
var user = UserManager.Find(...);
/* claim1 won't get persisted in a cookie */
var claim1 = new IdentityUserClaim
{ ClaimType = ClaimTypes.Country, ClaimValue = "Arctica", UserId = user.Id };
user.Claims.Add(claim1);
ClaimsIdentity identity = UserManager.CreateIdentity(
user, DefaultAuthenticationTypes.ApplicationCookie );
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = true }, identity );
如果我的假设是正确的,那么IdentityUserClaim
实例不持久化在 cookie 中的原因是否是因为假设这些声明应该存储在数据库中,因此可以在后续请求中从数据库中检索,而类型 Claim
的声明通常不存储在数据库中,因此为什么它们需要持久化在 cookie 中?
2(
如果您想更深入地了解它是如何工作的,请查看 武士刀项目的源代码
我认为 Asp.net 身份2不是Katana项目的一部分(也就是说,我看到有人问Microsoft什么时候发布 Asp.Net 身份的源代码,即使Katana源代码已经可用(?!
谢谢
好问题。甚至让我做了一个小实验。
这一行:
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = true }, identity );
不设置饼干。仅设置Identity
以后回调的对象。
Cookie 仅在将控件传递给中间件和一些称为 Response.OnSendingHeaders
的 OWIN 内部方法时设置。
因此,您的代码只是在存储在内存中供以后用户使用的identity
对象上添加claim2
。从理论上讲,您甚至可以在完成AuthenticationManager.SignIn
后设置claim1
。无论如何,它都会保留在饼干中。
如果您尝试在控制器中添加这样的 cliam:
public ActionResult AddNonPersistedClaim()
{
var identity = (ClaimsIdentity)ClaimsPrincipal.Current.Identity;
identity.AddClaim(new Claim("Hello", "World"));
return RedirectToAction("SomeAction");
}
不会在 Cookie 中设置此声明,您将不会在下一个请求中看到它。
如果您想更深入地了解它是如何工作的,请查看Katana项目的源代码,查看Microsoft.Owin.Security
和Microsoft.Owin.Security.Cookies
项目。随着AuthenticationManager
Microsoft.Owin.Net45
项目。
更新
要回答编辑 1 - IdentityUserClaim
确实会持久化到数据库中,这是将持久化声明分配给用户的方式。您可以通过UserManager
在用户身上添加这些内容
await userManager.AddClaimAsync(userId, new Claim("ClaimType", "ClaimValue"));
这会在数据库表中创建表示 IdentityUserClaim 的记录。下次用户登录时,将从数据库中读取这些声明并将其添加到标识中,并且可通过属性.Claims
或方法 .HasClaim()
在ClaimsIdentity.Current
上提供。
IdentityUserClaim
不做任何其他事情 - 只是将对象序列化Claim
数据库的方法。您通常不会直接访问这些内容,除非您想"裸露指关节"并自己写到该表上,而不是UserManager
。
换句话说 - 身份不会设置 cookie。OWIN 创建 Cookie。看看这段代码:
public async Task SignInAsync(IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent)
{
authenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.ApplicationCookie,
DefaultAuthenticationTypes.TwoFactorCookie,
DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie,
DefaultAuthenticationTypes.ExternalBearer);
var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Email, applicationUser.Email));
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
这里,身份验证管理器是 OWIN 的一部分。 Identity
是System.Security.Claims
的一部分。属于 Identity 项目的所有内容都是CreateIdentityAsync
方法 - 基本上是将用户从数据库转换为具有所有持久化角色和声明的ClaimsIdentity
。
回答你的编辑2:你是对的,AspNet Identity不是Katana项目的一部分,但Identity使用OWIN(Katana的一部分(进行cookie处理和授权。身份项目主要处理用户/角色/声明持久性和用户管理,如锁定、用户创建、发送密码重置电子邮件、2FA 等。
令我惊讶的是,ClaimsPrincipal以及ClaimsIdentity和Claim是.Net框架的一部分,可以在OWIN或Identity之外使用。这些不仅用于 Asp.Net,还用于Windows应用程序。好在.Net现在有开源,你可以浏览所有这些 - 让你更好地了解它是如何协同工作的。此外,如果您正在进行单元测试,了解内部结构是非常宝贵的,因此您可以在不使用模拟的情况下存根所有功能。
使用的是AD身份验证和asp core 2.1或2.2,则在配置名为ClaimActions的服务时,有一个选项OpenIdConnectOptions,在ClaimActions的帮助下,您可以编写继承ClaimActions的类[CustomClaimsFactory],该方法还覆盖了其Run方法,该方法实际上将设置持久声明,请在下面找到代码:
/* startup.cs */ services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.ClaimActions.Add(new CustomClaimsFactory(
"userName",
"xxxxx@outlook.com"
));
}
/*CustomClaimsFactory run method*/ public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
{
identity.AddClaim(new Claim(_ClaimType, _ValueType, issuer));
}