Entity framework core 如何将Blazor标识脚手架与自己的数据库上下文松散耦合?
我已经创建了一个Blazor服务器应用程序,可以选择构建一个身份系统。这创建了一个实体框架IdentityDbContext,其中包含许多表,用于管理用户登录和设置。我决定将我自己的DbContext与此分开,以便以后在必要时替换任何一个上下文 我想做的是在我自己的自定义dbcontext中有一个用户实体,并在其中存储对脚手架IdentityDbContext实体的用户id的引用。我还想确保,我不必在用户每次打开新页面时查询数据库中的自定义实体 我一直在四处寻找StackOverflow,试图找到如何解决这个问题的好建议,但我仍然不确定如何开始。所以我有几个问题:Entity framework core 如何将Blazor标识脚手架与自己的数据库上下文松散耦合?,entity-framework-core,blazor,identity,Entity Framework Core,Blazor,Identity,我已经创建了一个Blazor服务器应用程序,可以选择构建一个身份系统。这创建了一个实体框架IdentityDbContext,其中包含许多表,用于管理用户登录和设置。我决定将我自己的DbContext与此分开,以便以后在必要时替换任何一个上下文 我想做的是在我自己的自定义dbcontext中有一个用户实体,并在其中存储对脚手架IdentityDbContext实体的用户id的引用。我还想确保,我不必在用户每次打开新页面时查询数据库中的自定义实体 我一直在四处寻找StackOverflow,试图找
非常感谢您的帮助 看起来您的需求是存储当前用户的自定义信息,而不是当前用户的身份信息 对于更简单的用例,您可以创建自己的从IdentityUser派生的用户类,并在其上添加其他属性,让Identity负责所有持久性和检索 对于更复杂的用例,您可以遵循您所采取的方法,即创建您自己的表来存储与用户相关的信息 看来你采取了第二种方法 我的方法明智吗 我想是的。在标识表中隐藏大量关于用户的特定于业务的上下文将使您紧密地绑定到标识实现 我如何找到一个永久的身份证号码或字符串,以便在 用户身份
IdentityUser user=wait UserManager.FindByNameAsync(用户名);
字符串uniqueId=user.Id;
//或者,如果用户已登录。。。
字符串uniqueId=UserManager.GetUserId(HttpContext.User);
我是否应该将自定义用户实体存储在某种上下文中,以便
不必一直询问它?如果是,怎么做
假设您有一个来自您自己的DbContext的类结构,它存储关于用户的自定义信息,然后您可以在用户登录时检索该类结构,将其序列化,并将其放入ClaimsPrincipal上的声明中。这样,您就可以在每次请求时使用它,而无需返回数据库。您可以根据需要从Claims集合反序列化它,并根据需要使用它
如何。。。
创建CustomUserClaimsPrincipalFactory(当用户通过从ICustomUserInfoService检索数据并存储在声明中进行身份验证时,这将添加自定义声明):
公共类CustomUserClaimsPrincipalFactory
:UserClaimsPrincipalFactory
{
专用只读ICustomUserInfoService\u customUserInfoService;
公共CustomUserClaimsPrincipalFactory(
用户管理器用户管理器,
RoleManager RoleManager,
IOPS选项访问器,
ICustomUserInfoService(自定义用户信息服务)
:base(用户管理器、角色管理器、选项访问器)
{
_customUserInfoService=customUserInfoService;
}
受保护的覆盖异步任务GenerateClaimsAsync(
应用程序用户(用户)
{
var identity=await base.GenerateClaimsAsync(用户);
MyCustomUserInfo customUserInfo=
wait_customUserInfoService.GetInfoAsync();
//注:
//…若要添加更多索赔,需要注册索赔类型
//…在StartUp.cs中:配置服务
//例如
//services.AddIdentityServer()
//.addapi授权(选项=>
// {
//options.IdentityResources[“openid”].UserClaims.Add(“角色”);
//options.ApiResources.Single().UserClaims.Add(“角色”);
//options.IdentityResources[“openid”].UserClaims.Add(“我的自定义信息”);
//options.ApiResources.Single().UserClaims.Add(“我的自定义信息”);
// });
清单索赔=新清单
{
//将序列化的自定义用户信息添加到声明中
新声明(“我的自定义信息”,JsonSerializer.Serialize(customUserInfo))
};
identity.AddClaims(claims.ToArray());
返回身份;
}
}
在Startup.cs中注册CustomUserInfoService(从数据库获取自定义用户信息的您自己的服务):
services.AddScoped(=>newcustomuserinfoservice());
注册标识选项(使用您的CustomUserClaimsPrincipalFactory和Startup.cs中的授权。注意:将“我的自定义信息”添加为注册用户声明类型。如果没有此选项,您在CustomUserInfoService中的代码将无法添加声明类型“我的自定义信息”:
services.AddDefaultIdentity(选项=>
{
options.SignIn.RequireConfirmedAccount=false;
options.User.RequireUniqueEmail=true;
})
.AddRoles()
.AddEntityFrameworkStores()
.AddClaimsPrincipalFactory();
services.AddIdentityServer()
.addapi授权(选项=>
{
options.IdentityResources[“openid”].UserClaims.Add(“角色”);
options.ApiResources.Single().UserClaims.Add(“角色”);
options.IdentityResources[“openid”].UserClaims.Add(“我的自定义信息”);
options.ApiResources.Single().UserClaims.Add(“我的自定义信息”);
});
然后,您可以使用以下方法从声明中检索自定义用户信息,而无需返回数据库:
MyCustomUserInfo customUserInfo =
JsonSerializer.Deserialize<MyCustomUserInfo>(
HttpContext.User.Claims
.SingleOrDefault(c => c.Type == "my-custom-info").Value);
MyCustomUserInfo customUserInfo=
JsonSerializer.Deserialize(
HttpContext.User.Claims
.SingleOrDefault(c=>c.Type==“我的自定义信息”).Value);
谢谢您的回答!我最终使用AuthenticationStateProvider来查找我在
public class CustomUserClaimsPrincipalFactory
: UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
private readonly ICustomUserInfoService _customUserInfoService;
public CustomUserClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor,
ICustomUserInfoService customUserInfoService)
: base(userManager, roleManager, optionsAccessor)
{
_customUserInfoService= customUserInfoService;
}
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(
ApplicationUser user)
{
var identity = await base.GenerateClaimsAsync(user);
MyCustomUserInfo customUserInfo =
await _customUserInfoService.GetInfoAsync();
// NOTE:
// ... to add more claims, the claim type need to be registered
// ... in StartUp.cs : ConfigureServices
// e.g
//services.AddIdentityServer()
// .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
// {
// options.IdentityResources["openid"].UserClaims.Add("role");
// options.ApiResources.Single().UserClaims.Add("role");
// options.IdentityResources["openid"].UserClaims.Add("my-custom-info");
// options.ApiResources.Single().UserClaims.Add("my-custom-info");
// });
List<Claim> claims = new List<Claim>
{
// Add serialized custom user info to claims
new Claim("my-custom-info", JsonSerializer.Serialize(customUserInfo))
};
identity.AddClaims(claims.ToArray());
return identity;
}
}
services.AddScoped<ICustomUserInfoService>(_ => new CustomUserInfoService());
services.AddDefaultIdentity<IdentityUser>(options =>
{
options.SignIn.RequireConfirmedAccount = false;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddClaimsPrincipalFactory<CustomUserClaimsPrincipalFactory>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
options.IdentityResources["openid"].UserClaims.Add("my-custom-info");
options.ApiResources.Single().UserClaims.Add("my-custom-info");
});
MyCustomUserInfo customUserInfo =
JsonSerializer.Deserialize<MyCustomUserInfo>(
HttpContext.User.Claims
.SingleOrDefault(c => c.Type == "my-custom-info").Value);