我正在尝试为其创建API和网站客户端。最近我已经阅读了很多关于OAuth2作为安全机制的公司以及提供身份验证作为服务的公司,例如auth0.com甚至Azure活动目录,我可以看到使用它们的优势
因为我以前总是让用户在同一个数据库中,并且以一对多的形式与Users表有关系,如下面的
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等外部身份验证服务中,
在后一种情况下,类Invoice会不会像下面那样?
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.
答案 0 :(得分: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使用UUIDs使用户ID再次使生活变得简单):
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客户端(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 :(得分:3)
由于您已将Auth0称为身份提供者,因此有多种方法可以在数据库中实现用户表。 1.使用Auth0验证/注册用户将使用配置文件对象发送响应,该响应将包含您需要的所有基本配置文件信息。将此配置文件对象发布回您自己的API以将其保存到数据库。应使用您收到的访问令牌以及Auth0中的配置文件对象来保护此API端点。 2.您可以在Auth0中创建一个自定义规则,将用户信息发布回您的API。此规则在Auth0服务器上执行,因此这是一个安全的调用。 3.身份提供者(在我们的例子中为Auth0)需要公开API端点,该端点为我们提供用户配置文件数据(例如:https://yourdoamin.auth0.com/userinfo)。您可以从API调用此端点以接收用户信息。
当用户注册到您的应用程序时,请使用这些技术之一在数据库中建立用户配置文件信息表。将身份提供程序视为负责验证资源所有者(应用程序的用户)并提供访问令牌以安全访问API /应用程序的服务始终是一个好主意。如果您拥有数据库中用户的配置文件,则在用户通过身份验证后,您不必依赖身份提供程序。
如果您有任何其他问题,请与我们联系。
谢谢你, 索马。