将自定义数据存储在Identity Cookie中

时间:2016-04-08 09:29:25

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

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

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

1 个答案:

答案 0 :(得分:13)

您可以通过实施自定义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()
});