我有一个多租户REST应用。当新用户首次尝试访问我的应用程序(并假设他们的管理员已经授予他们的目录的应用程序权限)时,我在我的用户表中创建一个用户行并存储他们的姓名/电子邮件和其他字段。我在JwtBearerEvents的TokenValidated事件中执行此操作。
不幸的是,由于同时(并行请求)命中我的Web API,我最终会尝试插入多个用户行。我通过ObjectId为User做一个简单的SQL查询,然后在必要时创建。这不是线程安全的。我尝试将它包装在SQL事务中,但是选择不是阻塞,我不确定EF Core是否允许我执行锁定,我需要阻止其他选择完成。
我的代码基于TailSpin PnP,他们也在这里执行相同的逻辑。我的猜测是他们的站点逻辑在登录/登录过程中首先强制单个调用WEB API,如果新用户不存在则创建新用户。在我的流程中,使用多个HTTP GET直接点击REST API,我只需要验证标头中的承载令牌并让ADAL缓存它。
除了更改我的客户端逻辑,并强制第一次调用API成为单个HTTP GET之外,我还能在REST世界中如何工作?我无法使用SESSION逻辑来阻止同一会话中的其他呼叫。我不确定如何在整个服务器上执行锁定(仅当有一台服务器时才有效)。我可以使用DB层来保存写锁,但这看起来很脏。也许有更好的地方来创建新的用户逻辑?我还有其他方法可以安全地执行一次原子操作吗?
答案 0 :(得分:0)
根据描述,您似乎在用户调用REST API时以及验证令牌后创建用户记录(注册)。
要修复重复记录问题,一种可能的方法是将注册进度与令牌验证分开,与代码示例TailSpin PnP相同。例如,我们可以自定义令牌处理程序以验证用户是否注册并为用户注册提供UI。
另一种方法是,您可以使用锁顺序插入用户。例如,以下是供您参考的代码:
private Task tokenValidated(TokenValidatedContext context)
{
lock (obj)
{
//query db and insert users here
}
return Task.Delay(0);
}