2016-04-28 68 views
5

我正在尝试为其创建API和网站客户端。最近,我一直在阅读很多有关OAuth2作为安全机制以及提供身份验证即服务的公司,如auth0.com甚至Azure Active Directory,我可以看到使用它们的优势当用户存储在外部身份提供商服务中时与用户的关系

因为我习惯了永远让用户在同一个数据库和表格中以一对多的形式与用户表格关联,如下所示

public class User 
    { 
     public string subjectId { get; set; } 

     public virtual List<Invoice> Invoices { get; set; } 
     /* 
     More properties in here 
     */ 
    } 

public class Invoice 
    { 
     public int InvoiceId { get; set; } 
     public string PaymentNumber { get; set; } 
     public DateTime Date { get; set; } 
     public double Amount { get; set; } 
     public string Description { get; set; } 

     public virtual User User { get; set; } 
    } 

我的问题是这样的。

如果用户存储在外部认证服务,如Auth0.com,

  • 如何发票类将处理关系到用户?
  • 这是只是在发票表中添加一个新的属性subjectId,这将采取认证服务分配的任何id的值?

在后一种情况下,类的发票是否像下面的东西?

public class Invoice 
     { 
      public int InvoiceId { get; set; } 
      public string PaymentNumber { get; set; } 
      public DateTime Date { get; set; } 
      public double Amount { get; set; } 
      public string Description { get; set; } 

      public string SubjectId{get;set;} 
     } 

此外,如果用户存储在某处,你如何查询像,

Select * from Users u inner join Invoices i where Users.Name='John Doe' and i.Date>Somedate. 
+2

每OAuth的提供商为您提供了“用户id”成功认证后。用户ID在OAuth提供者中是唯一的。所以你必须存储信息:providername + userid。我通常创建一个至少有3个字段的[Users]表:MyUserID(int auto-inc或guid或...),ProviderName(字符串),ProviderUserID(字符串)。在你的情况下,我会把MyUserID放入你的发票中。 –

+0

感谢您的答案,你能告诉你如何提出疑问,如果用户存储在外部服务中,给我这个名称的每个用户都有发票吗? –

+0

“......至少3个字段”:)我总是创建一个更丰富的表格,其中包含OAuth提供者收到的更多信息:名字,姓氏,电子邮件等。有时我会添加包含本地信息的其他字段。同样,对于名字和姓氏,您可以决定是否从OAuth提供商获取它们,或者是在第一次创建用户时在本地添加它们。 –

回答

2

既然你提到Auth0为您的身份提供有多种方式来实现用户表在你的数据库中。 1.使用Auth0认证/注册用户将发送一个包含Profile对象的响应,该对象将拥有您所需的所有基本配置文件信息。将此配置文件对象发回您自己的API以将其保存到数据库。此API端点应使用您从Auth0收到的访问令牌和配置文件对象进行保护。 2.您可以在Auth0中创建自定义规则,将用户信息发送回您的api。此规则在Auth0服务器上执行,因此这是一个安全的调用。 3.我们需要身份提供者(在我们的例子中为Auth0)公开给我们用户配置文件数据的API端点(例如:https://yourdoamin.auth0.com/userinfo)。您可以通过API调用此端点来接收用户信息。

当用户注册到您的应用程序时,请使用以下技术之一在您的数据库中建立用户配置文件信息表。将身份提供者视为负责认证资源所有者(您的应用程序的用户)并提供安全访问您的API /应用程序的访问令牌的服务始终是个不错的主意。如果您的数据库中有该用户的配置文件,则在用户通过身份验证后,您无需依赖身份提供商。

如果您还有其他问题,请让我知道。

谢谢, Soma。

+0

我没有任何问题,你的答案很好。谢谢。我想我会选择2,这样我就不必依靠客户的开发人员将配置文件对象发回到api –

+0

很高兴我能够提供帮助。有关如何在Auth0中编写规则的文档的很好的来源。谢谢--soma –

4

我们为我们的网站设置了类似的设置。我们使用Passport作为我们的用户数据库,而我们的网站根本没有用户表。这使得生活比在Passport和我们的网站之间有大量重复数据要简单得多。我将使用我们的代码作为你正在做的事情的一个例子,希望它是有道理的。

我们的网站有一个许可对象,看起来像这样(的Java不是C#,但它们是相似的):

public class License { 
    public String companyName; 
    public List<User> users; 
} 

许可表看起来像这样(下调):

CREATE TABLE licenses (
    id   UUID   NOT NULL, 
    company_name VARCHAR(255) NOT NULL, 
    PRIMARY KEY (id) 
); 

该许可证通过这样的连接表来识别与其相关联的用户(Passport使用用户ID的UUID再次使生活变得简单):

CREATE TABLE users_licenses (
    users_id UUID NOT NULL, 
    licenses_id UUID NOT NULL, 
    PRIMARY KEY (users_id, licenses_id), 
    CONSTRAINT users_licenses_fk_1 FOREIGN KEY (licenses_id) REFERENCES licenses (id) 
); 

然后我们可以选择任一方向。如果我们知道用户ID,我们可以问他们所有的许可证是这样的:

select * from licenses where users_id = ? 

或者,如果我们知道的许可证ID,我们可以要求所有访问许可的用户:

select * from users_licenses where licenses_id = ? 

一旦我们有一个或多个用户ID,我们可以调用Passport /api/user端点或/api/user/search端点来检索一个或多个用户对象。我们实际上使用的是Passport Java Client(https://github.com/inversoft/passport-java-client),它会为我们调用API,然后返回List<User>。这是从上面存储在License类中的内容。该代码看起来是这样的:

License license = licenseMapper.retrieveById(licenseId); 
List<UUID> userIds = licenseMapper.retrieveUserIdsFor(licenseId); 
ClientResponse<SearchResponse, Errors> clientResponse = passportClient.searchUsers(userIds); 
license.users = clientResponse.successResponse.users; 

LicenseMapper是MyBatis的界面,执行SQL并返回许可对象。 C#ORM使用LINQ,但它会很相似。

这个设置的好处是,我们的网站数据库中没有user数据库表,我们必须保持同步。所有内容都通过API从Passport加载。我们也不关心表现。 Passport是内部部署的,每秒可以执行数千次用户查找,因此我们始终加载数据而不是缓存数据。

您需要额外代码的问题的唯一一部分是在您搜索像name='John Doe'这样的任意用户时处理连接。处理此问题的唯一方法是首先查询您的用户数据库,检索所有ID,然后加载其发票。这看起来像是一个庞大的用户数据库可能会很危险,但仍然可行。

这可能看起来像这样在我们的情况:

UserSearchCriteria criteria = new UserSearchCriteria().withName("John Doe"); 
ClientResponse<SearchResponse, Errors> clientResponse = passportClient.searchUsersByQueryString(criteria); 
List<User> users = clientResponse.successResponse.users; 
Set<License> licenses = new HashSet<>(); 
for (User user : users) { 
    licenses.addAll(licenseMapper.retrieveByUserId(user.id)); 
} 
+1

谢谢,这让我更清楚地知道其他人如何实现这些东西,这是我第一次处理外部auth服务器,并且我开始看到我的问题并不是唯一的,但我认为我将在api中添加一个用户表以及与其他实体的关系,这样我的代码将比为每个关系创建一个单独的表更简单 –

相关问题