【问题标题】:Store custom datas in Identity Cookie在身份 Cookie 中存储自定义数据
【发布时间】:2016-04-08 09:29:24
【问题描述】:

有没有办法将用户的一些自定义数据存储在 Identity API 生成的 cookie 中?

我们正在构建一个多租户应用程序,因此多个公司可以访问我们应用程序的同一个实例。这就是为什么对于特定用户,我需要将用户的公司代码存储在身份 cookie 中,以便在用户关闭浏览器后返回 Web 应用程序时检索用户的数据。

【问题讨论】:

  • 能否请您扩展您的 HttpContext 解决方案?我认为这可能是一个有用的参考。

标签: asp.net-core asp.net-identity-3


【解决方案1】:

您可以通过实现自定义 UserClaimsPrincipalFactory 并为您的商店编号添加自定义声明来实现此目的,然后它将与其他声明一起存储在 cookie 中。

下面是我的项目中的示例代码,我在其中添加了几个自定义声明,包括 SiteGuid,因为我的场景也是多租户

using cloudscribe.Core.Models;
using Microsoft.AspNet.Identity;
using Microsoft.Extensions.OptionsModel;
using System;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;

namespace cloudscribe.Core.Identity
{
    public class SiteUserClaimsPrincipalFactory<TUser, TRole> : UserClaimsPrincipalFactory<TUser, TRole>
    where TUser : SiteUser
    where TRole : SiteRole
{
    public SiteUserClaimsPrincipalFactory(
        ISiteRepository siteRepository,
        SiteUserManager<TUser> userManager,
        SiteRoleManager<TRole> roleManager, 
        IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
    {
        if (siteRepository == null) { throw new ArgumentNullException(nameof(siteRepository)); }

        siteRepo = siteRepository;
        options = optionsAccessor.Value;
    }

    private ISiteRepository siteRepo;
    private IdentityOptions options;

    public override async Task<ClaimsPrincipal> CreateAsync(TUser user)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }

        var userId = await UserManager.GetUserIdAsync(user);
        var userName = await UserManager.GetUserNameAsync(user);

        var id = new ClaimsIdentity(
            options.Cookies.ApplicationCookie.AuthenticationScheme,
            Options.ClaimsIdentity.UserNameClaimType,
            Options.ClaimsIdentity.RoleClaimType
            );

            id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId));
            id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName));

            if (UserManager.SupportsUserSecurityStamp)
            {
                id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
                await UserManager.GetSecurityStampAsync(user)));
            }

            if (UserManager.SupportsUserRole)
            {
                var roles = await UserManager.GetRolesAsync(user);
                foreach (var roleName in roles)
                {
                    id.AddClaim(new Claim(Options.ClaimsIdentity.RoleClaimType, roleName));
                    if (RoleManager.SupportsRoleClaims)
                    {
                        var role = await RoleManager.FindByNameAsync(roleName);
                        if (role != null)
                        {
                            id.AddClaims(await RoleManager.GetClaimsAsync(role));
                        }
                    }
                }
            }
            if (UserManager.SupportsUserClaim)
            {
                id.AddClaims(await UserManager.GetClaimsAsync(user));
            }

            ClaimsPrincipal principal = new ClaimsPrincipal(id);

            if (principal.Identity is ClaimsIdentity)
            {
                ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;

                Claim displayNameClaim = new Claim("DisplayName", user.DisplayName);
                if (!identity.HasClaim(displayNameClaim.Type, displayNameClaim.Value))
                {
                    identity.AddClaim(displayNameClaim);
                }

                Claim emailClaim = new Claim(ClaimTypes.Email, user.Email);
                if (!identity.HasClaim(emailClaim.Type, emailClaim.Value))
                {
                    identity.AddClaim(emailClaim);
                }

                ISiteSettings site = await siteRepo.Fetch(user.SiteId, CancellationToken.None);

                if (site != null)
                {
                    Claim siteGuidClaim = new Claim("SiteGuid", site.SiteGuid.ToString());
                    if (!identity.HasClaim(siteGuidClaim.Type, siteGuidClaim.Value))
                    {
                        identity.AddClaim(siteGuidClaim);
                    }

                }      

            }

            return principal;

        }
    }
}

然后在 Startup 中,您需要注册您的自定义工厂,以便注入和使用它而不是默认工厂

services.AddScoped<IUserClaimsPrincipalFactory<SiteUser>, SiteUserClaimsPrincipalFactory<SiteUser, SiteRole>>();

另一种方法是使用声明转换,但是这种方法不会将额外声明存储在 cookie 中,而是更新每个请求的声明,也就是说,它会在请求的生命周期内向来自 cookie 的声明添加更多声明但不会修改 cookie 中的声明。

public class ClaimsTransformer : IClaimsTransformer
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("ProjectReader", "true"));
        return Task.FromResult(principal);
    }
}

然后在startup.cs中:

app.UseClaimsTransformation(new ClaimsTransformationOptions
{
    Transformer = new ClaimsTransformer()
});

【讨论】:

  • 谢谢它的工作!我绕过了关于 UserClaimsPrincipalFactory 的所有内容,因为它对我们的使用来说太复杂了,当我需要它来登录时我只是使用 HttpContext。我又添加了两个 Claim 并且我能够恢复关于我的应用程序第二次使用的信息! :)
  • Joe,使用这种方法,cookie 是否可以被篡改,例如恶意用户将其 cookie 的“SiteGuid”编辑为其他内容?授予一个有效的 Guid 很难猜测,但我正在考虑使用简单的 AccountId(数据库中的键值)来过滤用户对数据的访问。这安全吗?
  • 我认为微软正在使用数据保护 api 来加密存储在 auth cookie 中的角色和声明
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2023-03-24
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 2019-09-05
相关资源
最近更新 更多