具有自己身份表的多个数据库应与单个Web API连接并验证jwt令牌

时间:2018-07-06 02:19:30

标签: asp.net-web-api2 asp.net-identity jwt multi-tenant asp.net-authorization

我正在为几个公司进行相同的项目,因此我们为具有相同数据库结构的不同公司创建了不同的数据库,每个数据库都有自己的标识表,基于角色的菜单,基于角色的访问权限。

我已经编写了一个api来根据提供的用户名连接不同的数据库。因为所有公司都使用相同的登录屏幕登录。

我们通过登录屏幕上传递的用户名来确定要连接的数据库。

示例: 3家公司-abc.com,pqr.com,xyz.com 单一登录屏幕-www.example.com/login 在登录屏幕上,用户将使用其公司电子邮件登录 user @ abc.com,user @ pqr.com,user @ xyz.com

登录后一切正常

问题是: jwt令牌路径始终连接到abc.com数据库,尽管这些记录在其dbs中,但始终会显示user@pqr.com和user@xyz.com的错误消息。

注意 1)将来的公司将会增加,因为这些是我们未来门户数据库的门户的客户-abc.com,bcd.com,def.com .......等。

2)公司所有者可能有多个拥有不同数据库的公司,因此他们需要查看来自两个数据库的报告。 像X先生拥有2家公司(abc.com&pqr.com)一样,尽管公司所有者在不同的数据库中拥有不同的帐户,他可能只需要查看很少的报告就需要两个数据库的数据。

完成此操作后,除以下一项外,所有问题均已解决: 我已替换    // var userManager = context.OwinContext.GetUserManager(); with

var appDbContext =新的ApplicationDbContext(context.UserName);             HttpContext.Current.GetOwinContext()。Set(appDbContext);             HttpContext.Current.GetOwinContext()。Set(新ApplicationUserManager(新Microsoft.AspNet.Identity.EntityFramework.UserStore(appDbContext))));             var userManager = HttpContext.Current.GetOwinContext()。GetUserManager();

在类中-ApplicationOAuthProvider

请注意,没有完成2。##-感谢您的帮助

我正在寻找让我感到困惑的永久解决方案。 我们非常感谢您的协助。

1 个答案:

答案 0 :(得分:0)

是的

1)您应该准备在多个虚拟/物理服务器之间配置信任。这是JWT的主要优点,因为它可以联合。这与Web应用程序之外的数据库无关。如果要为此应用程序使用多个Web服务器,则它们需要彼此信任。

我相信您可以尝试以下方法之一

i)将您的身份验证服务器编码/配置为解决方案中的域/机器可信任

请参阅https://blogs.msdn.microsoft.com/webdev/2017/04/06/jwt-validation-and-authorization-in-asp-net-core/

特别注意“受众”和“授权”字符串,并研究这些概念。

ii)将外部JWT视为适当的“外部”凭证(例如Google OAuth),然后在引用外部令牌后初始化本地JWT或其他安全机制。我将为此找到参考。

2)您应该为每个客户有一个单独的子域(水平规则后,请参见下文)

3)您必须修复初始化数据库上下文的策略。 GetOwinContext方法是IoC模式的糟糕实现。默认的JWT UserManager代码期望db上下文是从OwinContext单例引用派生的。如果要访问多个数据库,这是一个问题。一种方法是现在仅按需构造上下文,然后考虑稍后优化重用和性能的方法。这可能很重要,因为您需要确保它针对任何给定查询都检查正确的数据库。

这里是一个解决方案链接:How to change database name in dbcontext connection string at runtime

4)您的客户需要访问多个数据库。有几种方法可以做到这一点。理想情况下,您将尽可能地维护联盟模式。但是您可能还需要/需要服务器端业务流程:CRUD之外的特殊API,专用于多数据库任务。每个固定报告将有一个服务器端操作。这样的服务器端操作将查看针对数据库查询的请求(就CustomerID而言),它将通过自定义JWT声明(一组CustomerID)来验证访问,如果有任何指定的customerid,则将引发异常不允许。然后,该功能将根据需要使用那些经过验证的客户ID执行。参见[5]如何运行。

以下是一些用于创建自定义JWT声明的链接(这些链接存储在JWT中,通常通过Bearer标头与客户端进行传输):

以下是获取自定义JWT声明的一些链接:

5)对一个联合数据集进行排序是很常见的。这可能是您的情况。如果数据库位于同一RDBMS实例上,则通常可以在一个SQL语句(对于SQL Server)中运行多数据库查询。 (但是,如果您使用的是Azure数据库池,它们通常将(透明地)运行在不同的实例上。我相信最近的更改允许您指定它们在同一实例上,或者现在允许多数据库查询)。否则,服务器端编排意味着您将分别从每个数据库中获得前十名,然后执行最终排序,然后执行前十名将其发送回客户端。最坏的情况是,您需要客户端多次查询,一次针对每个客户ID /数据库,然后在客户端汇总数据。

(我已经讲了很多点,请告诉我您想进一步了解的细节)


我喜欢每个客户的数据库

您似乎正在描述一个系统,其中每个客户都有一个单独的数据库。当您与不需要应用程序内共享数据的客户打交道时,这是我大力提倡的设计。它隔离了数据访问(安全性/隐私性),减少了表锁定争用(性能),并使您可以将数据库移动到其他服务器以实现邻近性和负载平衡(性能)。

all company logins with same login screen.

此要求是您最大的障碍。如果您曾经使用过Slack,您会注意到他们为每个团队设置了一个新的子域。无需每个团队都共享凭据。

这种具有单独子域的设计意味着:

  • Web服务器也是便携式组件;除了数据库。
  • 客户可以将自己的DNS记录设置为别名URL(即yourapp.acmeco.com);以及您自己的默认子域(即acmeco.yourapp.com)

不管您的具体问题有什么答案,我强烈建议您与项目的利益相关者交谈,以查看是否可以实现多个子域设计。

为便于配置(针对Web应用程序),我强烈建议:

  • 设置通配符DNS记录(我知道至少CloudFlare支持此记录)
  • 您应该获得通配符SSL证书,以便轻松加密每个子域。 1-2年的费用约为100美元。不要为更多功能付费,这是IMO的浪费。
  • 配置没有特定主机的Web服务器。 (如果您将其他Web应用程序配置了相同的IP,则它们仍可以具有主机名并共享端口80/443)。使用IIS,这仅意味着将“主机URL”区域留为空白。
  • 您将需要您的应用程序来处理JWT / Session,以检查要连接的数据库。登录时,您需要检查Host标头以确定要连接到的数据库。