Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有多租户数据访问的Web API身份验证_C#_Authentication_Oauth 2.0_Asp.net Web Api2_Owin - Fatal编程技术网

C# 具有多租户数据访问的Web API身份验证

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作为声明,消除对内存缓存的需求,从而使

我不确定我是否使用了正确的标题,但我想不出更好的方式来描述它。这可能更像是一个设计问题

我有一个多租户数据库,其中一个用户可以属于一个或多个实体。我通过调用/token端点使用用户的凭据对其进行身份验证

收到令牌后,我调用自己的端点(使用令牌)获取该用户的可用实体列表,然后允许该用户在内存缓存中设置其当前实体。然后,我使用这个内存缓存查找以下所有请求的实体/租户ID,以了解用户在调用DB时“登录”的实体/租户

理想情况下,我希望通过在令牌中包含实体/租户ID作为声明,消除对内存缓存的需求,从而使我的应用程序更无状态,但我仅在用户进行身份验证并选择其实体后才知道此ID。很明显,我不能在令牌发出后更改或添加声明,但是是否有替代设计来实现这种行为

我考虑过每个租户可能使用一个子域,但从技术上讲,这更难设置和维护。我还考虑过提示用户输入他/她希望以自由文本形式登录的实体,并附上他们的凭据,但这并不理想


以前有人面临过这个挑战吗?

我同意您的观点,租户选择必须以无状态的方式进行,以避免在基于REST的体系结构中进行有状态交互。缓存方法可能会导致许多陷阱,并引入对基于会话的交互的强烈依赖

我可以想出两个主要的选项来使租户选择无状态:

  • 基于URI的选择:您可以向API中添加租户参数,在所有控制器之间共享。类似于此的映射:
    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)
        {
            //...
    
  • < > > > >基于头的选择< /强>:您可以考虑添加一个自定义HTTP头,它包含关于所选租户的信息:例如:代码> X-TANTANTION:TenantId < /Cord>,然后您可以读取该头,或者在WebAPI之前执行<代码> OWNIDealSudio,并设置上下文变量。(甚至用户声明将持续当前请求)在控制器内使用

    当然,在这两种情况下,您都必须在返回数据之前验证当前用户是否可以访问所选租户


    坦率地说,我会排除在访问令牌中包含tenantId的可能性,子域方法对我来说太复杂了。

    实际上,我不确定tenant是否应该以无状态的方式实现。tenant可能是身份验证的一部分,因此它应该保持在状态(与用户完全相同)。如果租户是身份验证的一部分,我们应该能够从承载中检索租户,就像我们对用户所做的一样

    在我的例子中,我将用户存储在租户中,而存储在一个租户中的joe与存储在另一个租户中的joe不同。因此,当服务器接收到承载时,它不仅可以检索用户名,还需要检索租户

    我已经写了一个概念证明。它缺少组管理(所以您不能使用控制器中的属性来检查组授权)

    它在这里发布

    非常感谢您的回答。这正是我想要的。“排除在访问令牌中包含租户的可能性”-我同意。访问令牌应该用于识别请求者的属性,而不是请求本身。也就是说,它表明了他们可以做什么,而不是他们想做什么。混合使用这两种方法可能会有问题的一个例子是,如果用户可以访问多个租户,那么他们的令牌可能包含多个租户id。你不认为包括t吗访问令牌中的enantId更易于维护。前端人员只发送整个令牌,然后根据访问令牌过滤数据?REST是无状态的,OAuth2不是。访问令牌与服务器上的其他信息相关(至少用户名)因此,我认为在这些信息中添加TenantId并不是那么糟糕。当然,只有当用户TenantId是1-1关系时,这才有效。