将自定义数据存储在身份 Cookie 中
Store custom datas in Identity Cookie
有没有办法将用户的一些自定义数据存储在身份 API 生成的 cookie 中?
我们正在构建一个多租户应用程序,因此多个公司可以访问我们应用程序的同一个实例。这就是为什么对于特定用户,我需要将用户的公司代码存储在身份 cookie 中,以便在用户关闭浏览器后返回 Web 应用程序时从用户那里检索数据。
您可以通过实施自定义 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>>();
另一种方法是使用 Claims Transformation,但是这种方法不会将额外的声明存储在 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()
});
有没有办法将用户的一些自定义数据存储在身份 API 生成的 cookie 中?
我们正在构建一个多租户应用程序,因此多个公司可以访问我们应用程序的同一个实例。这就是为什么对于特定用户,我需要将用户的公司代码存储在身份 cookie 中,以便在用户关闭浏览器后返回 Web 应用程序时从用户那里检索数据。
您可以通过实施自定义 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>>();
另一种方法是使用 Claims Transformation,但是这种方法不会将额外的声明存储在 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()
});