gpt4 book ai didi

c# - ASP.Net Core MVC Identity - 添加临时( session )声明

转载 作者:行者123 更新时间:2023-12-04 16:03:52 25 4
gpt4 key购买 nike

对于初学者来说,这个问题也在这里( Temporary Session Based Claims in ASP.NET Core Identity )和这里( How to add claim to user dynamically? )被问到,但是这两个问题都没有得到答案,所以我试图恢复它......

我正在创建一个 Multi-Tenancy Web 应用程序。用户登录后,可以看到与自己公司相关的数据(但不能看到使用该应用程序的其他公司的数据)。由于特许经营集团拥有多个店面等,单个用户要求访问多个不同公司的情况并不少见,但在这种情况下,他们在登录时必须选择单个公司。

几乎所有的数据查询都需要一个公司 ID 作为参数,所以我需要一种方便的方法来检查用户当前登录的是哪家公司。如果他们注销并登录不同的公司,我需要查看不同的公司 ID。我想将它存储为我在 session 期间可以看到的身份声明,但我不一定要将它存储到数据库中,因为它可能会随着每次登录而改变。

这是我的登录操作(基于标准的 ASP.Net Core MVC 模板):

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
// BEGIN CUSTOM CODE - Check which companies a user can access
IEnumerable<int> allCompanies = _myDbService.GetUserCompanies(model.Email);

if (allCompanies.Count() == 1)
{
// then they can only access one company - log them into it automatically.
// I need easy access to its ID with the User since it is used with almost every db query.

int companyID = allCompanies[0];
((ClaimsIdentity)User.Identity).AddClaim(new Claim("CompanyID", companyID.ToString())); // this shows as null on future controller actions.

Debug.WriteLine("Set breakpoint here to examine User"); // I see 1 claim (my custom claim) in the debugger, but it is not in the database yet.

// future controller actions show me 3 claims (nameidentifier, name, and security stamp) but User.Claims.First(c => c.Type == "CompanyID").Value throws error.

return RedirectToLocal(returnUrl);
}
else
{
// the user has access to several companies - make them choose one to complete login process
RedirectToAction("ChooseCompany", new { companyList = allCompanies });
}
// END CUSTOM CODE
}

// REMAINING CODE OMITTED FOR BREVITY
}

// If we got this far, something failed, redisplay form
return View(model);
}

所以我的问题是:为什么自定义声明不“粘住”以便在 future 的 Controller 操作中可以看到它?如果这是标准行为,为什么不将其保存到数据库中?有没有办法在不使用 AddSession() 的情况下在 session 期间保持这个值?如果我将其作为声明来实现,那么每次访问该值时我是否都要往返于数据库?

最佳答案

对于有此问题的其他任何人,这是我到目前为止的位置......要将声明永久存储在数据库中并在登录时自动加载它,您必须使用以下内容并且更改将在下次登录之前生效:

await userManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));

使用以下内容只会存储当前 session 的声明,所以我在正确的轨道上:
((ClaimsIdentity)User.Identity).AddClaim(new Claim("your-claim", "your-value"));

我发现在 Controller 操作之间获得“坚持”声明的唯一方法是覆盖 UserClaimsPrincipalFactory,以便 ASP.Net 将您的自定义代码用作登录过程的一部分。这里的问题是您只能访问相关方法中的 ApplicationUser,并且您无法真正传入任何自定义参数 AFAIK。所以我首先通过 ApplicationUser 类修改如下:
public class ApplicationUser : IdentityUser
{
public long ActiveDealershipID { get; set; }
}

(您必须应用 EF 迁移)。现在我创建一个从 UserClaimsPrincipalFactory 派生的类,如下所示:
public class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public MyClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> options) : base(userManager, roleManager, options)
{
}

public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);

long dealershipID = user.ActiveDealershipID;
((ClaimsIdentity)principal.Identity).AddClaim(new Claim("DealershipID", dealershipID.ToString()));

return principal;
}
}

(必须在startup.cs的ConfigureServices中注册服务):
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyClaimsPrincipalFactory>();

然后在我的登录操作中,我在登录之前从模型数据设置新的用户属性,以便在设置声明时它可用于 UserClaimsPrincipalFactory:
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
ApplicationUser user = await _userManager.FindByEmailAsync(model.Email);
user.ActiveDealershipID = model.ChosenDealership
await _userManager.UpdateAsync(user);

var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
...

我仍然愿意接受更好的建议或其他想法,但这似乎对我有用。

关于c# - ASP.Net Core MVC Identity - 添加临时( session )声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49578493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com