2016-04-28 51 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中添加一個用戶表以及與其他實體的關係,這樣我的代碼將比爲每個關係創建一個單獨的表更簡單 –

相關問題