【发布时间】:2018-01-24 13:44:34
【问题描述】:
我们在 .NET Core 上运行 IdentityServer4。目前用户使用他们的 AzureAD 帐户登录 - 如果在数据库中找不到用户名,那么我们会查询 Microsoft 的 Graph API 以获取他们的组、一般信息等。
最近一个应用程序几乎背靠背地发出了两个登录请求 - 由于用户不存在,它进行了查询并将他们的帐户添加到数据库中两次。
我一直在寻找解决此问题的最佳方法,但从我所阅读的内容来看,几乎所有解决方案都被认为是不好的做法。
设置是这样的 - 用户登录后被定向到 AccountController - ExternalLoginCallback:
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
....
var user = await _users.AutoProvisionUser(provider, userId, externalUser, access_token, _options); // _users is the UserStore class
...
}
AutoProvisionUser 如下所示:
public async Task<User> AutoProvisionUser(string provider, string userId, ClaimsPrincipal principal, string accessToken, Globals globals)
{
var user = await GetFullUserByUsernameAsync(principal.FindFirstValue(ClaimConstants.UPN));
if (user.Account == null)
{
user = await CreateUserAsync(principal, userId, accessToken, globals.AzureApplication);
}
else
{
await UpdateGroupsAsync(user.Account, accessToken, globals.AzureApplication);
}
return new User
{
Claims = principal.Claims.ToList(),
Name = user.Profile.DisplayName,
Provider = provider,
SubjectId = user.Account.AzureId,
Username = user.Account.UserName
};
}
public async Task<UserIdentity> CreateUserAsync(ClaimsPrincipal principal, string userId, string graphAccessToken,
AzureApplication options)
{
// API calls to Microsoft, adding them to the database and then returning the user...
}
我一直在考虑创建一种方法,将所有任务排队并等待它们完成后再继续 - 这会解决问题还是另一个请求会简单地启动一个新线程并忽略当前执行?
我也一直在考虑添加一个自定义 DelegateHandler 并尝试在那里使用一些逻辑来查看我是否能够过滤掉“重复”请求。
我认为最好的情况是,如果发出另一个重复请求,应用程序会等待当前正在运行的任何 CreateUserAsync 任务,然后再执行 user.Account == null强>检查。这是否可行?如果可以,是否可以通过包装我上面提到的任务来实现?
【问题讨论】:
-
数据库中没有唯一索引来防止重复帐户?
-
目前没有,但这可能是前进的方向。
标签: c# asp.net-web-api async-await identityserver4