坚持要求的索赔

时间:2014-08-13 17:06:36

标签: c# .net asp.net-mvc asp.net-identity-2

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()注销时,两个声明也会被删除,因此下次此用户登录< / strong>,它不再是这些两个声明的成员(我认为两个声明不再存在)

claim2在请求中保留的事实(即使在向用户添加claim2时已创建身份验证Cookie )表明声明请不要通过身份验证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)

  

如果您想深入了解一切是如何运作的,请查看   Katana项目的源代码

我认为 Asp.net Identity 2 不是 Katana项目的一部分(也就是说,我看到有人问微软什么时候会发布 Asp.Net Identity的源代码,即使 Katana源代码已经可用)?!

谢谢

2 个答案:

答案 0 :(得分:11)

好问题。甚至让我做了一个小实验。

这一行:

AuthenticationManager.SignIn(
          new AuthenticationProperties { IsPersistent = true }, identity );

不设置Cookie。仅为后面的回调设置Identity对象。

Cookie仅在控件传递给中间件和一些名为Response.OnSendingHeaders的OWIN内部方法时设置。

因此,您的代码只是在claim2对象上添加identity,该对象存储在内存中供以后用户使用。理论上,您甚至可以在完成claim1后设置AuthenticationManager.SignIn。无论如何它都将保留在cookie中。

如果您尝试在控制器中添加这样的cliam:

    public ActionResult AddNonPersistedClaim()
    {
        var identity = (ClaimsIdentity)ClaimsPrincipal.Current.Identity;
        identity.AddClaim(new Claim("Hello", "World"));

        return RedirectToAction("SomeAction");
    }

此声明不会在Cookie中设置,您将不会在下一个请求中看到它。

如果您想深入了解一切是如何运作的,请查看Katana Project的源代码,查看Microsoft.Owin.SecurityMicrosoft.Owin.Security.Cookies个项目。与AuthenticationManager项目中的Microsoft.Owin.Net45一起。

<强>更新

要回答您的编辑1 - IdentityUserClaim确实存在于数据库中,这是您可以将持久声明分配给用户的方式。您可以通过UserManager

在用户上添加这些内容
await userManager.AddClaimAsync(userId, new Claim("ClaimType", "ClaimValue"));

这将在数据库表中创建表示IdentityUserClaim的记录。当用户下次登录时,会从数据库中读取这些声明并将其添加到身份中,并通过ClaimsIdentity.Current.Claims方法在.HasClaim()上提供。

IdentityUserClaim没有做任何其他事情 - 只是将Claim对象序列化到数据库中。您通常不会直接访问这些内容,除非您想要去指关节&#34;并在UserManager之外自己写入该表。

换句话说 - Identity不会设置cookie。 OWIN创建cookie。看看this piece of code

    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以及ClaimsIdentityClaim是.Net框架的一部分,可以在OWIN或Identity之外使用。这些不仅用于Asp.Net,还用于Windows应用程序。好的事情.Net现在有开源,您可以浏览所有这些 - 让您更好地了解它们如何一起工作。此外,如果您正在进行单元测试,那么了解内部结构是非常宝贵的,因此您可以在不使用模拟的情况下存根所有功能。

答案 1 :(得分:0)

如果您使用的是AD身份验证和ASP核心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));

    }