跨请求保留声明


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);

claim1claim2仅在用户登录时跨请求保留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.SecurityMicrosoft.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 的一部分。 IdentitySystem.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));
    }

最新更新