C# 具有多租户数据访问的Web API身份验证
我不确定我是否使用了正确的标题,但我想不出更好的方式来描述它。这可能更像是一个设计问题 我有一个多租户数据库,其中一个用户可以属于一个或多个实体。我通过调用/token端点使用用户的凭据对其进行身份验证 收到令牌后,我调用自己的端点(使用令牌)获取该用户的可用实体列表,然后允许该用户在内存缓存中设置其当前实体。然后,我使用这个内存缓存查找以下所有请求的实体/租户ID,以了解用户在调用DB时“登录”的实体/租户 理想情况下,我希望通过在令牌中包含实体/租户ID作为声明,消除对内存缓存的需求,从而使我的应用程序更无状态,但我仅在用户进行身份验证并选择其实体后才知道此ID。很明显,我不能在令牌发出后更改或添加声明,但是是否有替代设计来实现这种行为 我考虑过每个租户可能使用一个子域,但从技术上讲,这更难设置和维护。我还考虑过提示用户输入他/她希望以自由文本形式登录的实体,并附上他们的凭据,但这并不理想C# 具有多租户数据访问的Web API身份验证,c#,authentication,oauth-2.0,asp.net-web-api2,owin,C#,Authentication,Oauth 2.0,Asp.net Web Api2,Owin,我不确定我是否使用了正确的标题,但我想不出更好的方式来描述它。这可能更像是一个设计问题 我有一个多租户数据库,其中一个用户可以属于一个或多个实体。我通过调用/token端点使用用户的凭据对其进行身份验证 收到令牌后,我调用自己的端点(使用令牌)获取该用户的可用实体列表,然后允许该用户在内存缓存中设置其当前实体。然后,我使用这个内存缓存查找以下所有请求的实体/租户ID,以了解用户在调用DB时“登录”的实体/租户 理想情况下,我希望通过在令牌中包含实体/租户ID作为声明,消除对内存缓存的需求,从而使
以前有人面临过这个挑战吗?我同意您的观点,租户选择必须以无状态的方式进行,以避免在基于REST的体系结构中进行有状态交互。缓存方法可能会导致许多陷阱,并引入对基于会话的交互的强烈依赖 我可以想出两个主要的选项来使租户选择无状态:
api/{tenantId}/{controller}/{id}
可以让您以一种简单的方式在客户端租户之间切换。这可以使用基于约定的路由:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{tenantId}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
或者在控制器上使用基于属性的路由:
[RoutePrefix("api/{tenantId}/myentities")]
public class EntityController : ApiController
{
[Route("")]
public IHttpActionResult GetAllEntities(string tenantId)
{
//...
坦率地说,我会排除在访问令牌中包含tenantId的可能性,子域方法对我来说太复杂了。实际上,我不确定tenant是否应该以无状态的方式实现。tenant可能是身份验证的一部分,因此它应该保持在状态(与用户完全相同)。如果租户是身份验证的一部分,我们应该能够从承载中检索租户,就像我们对用户所做的一样 在我的例子中,我将用户存储在租户中,而存储在一个租户中的joe与存储在另一个租户中的joe不同。因此,当服务器接收到承载时,它不仅可以检索用户名,还需要检索租户 我已经写了一个概念证明。它缺少组管理(所以您不能使用控制器中的属性来检查组授权) 它在这里发布
非常感谢您的回答。这正是我想要的。“排除在访问令牌中包含租户的可能性”-我同意。访问令牌应该用于识别请求者的属性,而不是请求本身。也就是说,它表明了他们可以做什么,而不是他们想做什么。混合使用这两种方法可能会有问题的一个例子是,如果用户可以访问多个租户,那么他们的令牌可能包含多个租户id。你不认为包括t吗访问令牌中的enantId更易于维护。前端人员只发送整个令牌,然后根据访问令牌过滤数据?REST是无状态的,OAuth2不是。访问令牌与服务器上的其他信息相关(至少用户名)因此,我认为在这些信息中添加TenantId并不是那么糟糕。当然,只有当用户TenantId是1-1关系时,这才有效。