使用 Azure Cosmos DB 檔資料庫驗證使用者和 Xamarin.Forms

Download Sample 下載範例

Azure Cosmos DB 檔案資料庫支援分割的集合,可跨越多部伺服器和分割區,同時支援無限制的記憶體和輸送量。 本文說明如何結合訪問控制與分割集合,讓使用者只能在應用程式中存取自己的檔 Xamarin.Forms 。

概觀

建立分割區集合時,必須指定分割區索引鍵,且具有相同分割區索引鍵的檔會儲存在相同的分割區中。 因此,將使用者的身分識別指定為分割區索引鍵,將會導致只儲存該使用者文件的數據分割集合。 這也可確保 Azure Cosmos DB 檔資料庫會隨著使用者和項目數目增加而調整。

存取權必須授與任何集合,而適用於 NoSQL 的 Azure Cosmos DB 存取控制模型定義兩種類型的存取建構:

  • 主要密鑰 可啟用 Azure Cosmos DB 帳戶內所有資源的完整系統管理存取權,並在建立 Azure Cosmos DB 帳戶時建立。
  • 資源令牌 會擷取資料庫用戶與用戶對於特定 Azure Cosmos DB 資源的許可權之間的關聯性,例如集合或檔。

公開主要密鑰會開啟 Azure Cosmos DB 帳戶,以致惡意或疏忽使用的可能性。 不過,Azure Cosmos DB 資源令牌提供安全的機制,可讓客戶端根據授與的許可權讀取、寫入和刪除 Azure Cosmos DB 帳戶中的特定資源。

向行動應用程式要求、產生及傳遞資源令牌的一般方法是使用資源令牌代理程式。 下圖顯示範例應用程式如何使用資源令牌代理程式來管理檔資料庫資料的存取權的高階概觀:

Document Database Authentication Process

資源令牌代理程式是裝載於 Azure App 服務 的中層 Web API 服務,其擁有 Azure Cosmos DB 帳戶的主要密鑰。 範例應用程式會使用資源令牌代理程式來管理檔資料庫數據的存取,如下所示:

  1. 在登入時,應用程式會Xamarin.Forms連絡 Azure App 服務 以起始驗證流程。
  2. Azure App 服務 使用Facebook執行OAuth驗證流程。 驗證流程完成之後, Xamarin.Forms 應用程式會收到存取令牌。
  3. 應用程式 Xamarin.Forms 會使用存取令牌向資源令牌代理程式要求資源令牌。
  4. 資源令牌代理程式會使用存取令牌向Facebook要求使用者的身分識別。 接著,使用者身分識別會用來向 Azure Cosmos DB 要求資源令牌,以授與已驗證使用者分割集合的讀取/寫入存取權。
  5. 應用程式 Xamarin.Forms 會使用資源令牌,直接存取具有資源令牌所定義許可權的 Azure Cosmos DB 資源。

注意

資源令牌到期時,後續的文件資料庫要求將會收到 401 未經授權的例外狀況。 此時, Xamarin.Forms 應用程式應該重新建立身分識別,並要求新的資源令牌。

如需 Azure Cosmos DB 數據分割的詳細資訊,請參閱 如何在 Azure Cosmos DB 中分割和調整。 如需 Azure Cosmos DB 存取控制的詳細資訊,請參閱在適用於 NoSQL 的 Azure Cosmos DB 中保護對 Azure Cosmos DB 數據的存取和存取和存取控制。

設定

將資源權杖代理程式整合到 Xamarin.Forms 應用程式的程式如下:

  1. 建立將使用訪問控制的 Azure Cosmos DB 帳戶。 如需詳細資訊,請參閱 Azure Cosmos DB 組態
  2. 建立 Azure App 服務 來裝載資源令牌代理程式。 如需詳細資訊,請參閱 Azure App 服務 組態
  3. 建立 Facebook 應用程式以執行驗證。 如需詳細資訊,請參閱 Facebook 應用程式組態
  4. 設定 Azure App 服務 以使用 Facebook 執行簡單的驗證。 如需詳細資訊,請參閱 Azure App 服務 驗證組態
  5. 設定Xamarin.Forms範例應用程式以與 Azure App 服務 和 Azure Cosmos DB 通訊。 如需詳細資訊,請參閱 Xamarin.Forms 應用程式組態

注意

如果您沒有 Azure 訂用帳戶,請在開始之前建立 免費帳戶

Azure Cosmos DB 組態

建立將使用存取控制的 Azure Cosmos DB 帳戶的程式如下:

  1. 建立 Azure Cosmos DB 帳戶。 如需詳細資訊,請參閱 建立 Azure Cosmos DB 帳戶
  2. 在 Azure Cosmos DB 帳戶中,建立名為 UserItems的新集合,並指定的數據 /userid分割索引鍵。

Azure App 服務 組態

在 Azure App 服務 中裝載資源權杖代理程式的程式如下所示:

  1. 在 Azure 入口網站 中,建立新的 App Service Web 應用程式。 如需詳細資訊,請參閱在 App Service 環境 中建立 Web 應用程式。

  2. 在 Azure 入口網站 中,開啟 Web 應用程式的 [應用程式 設定] 刀鋒視窗,然後新增下列設定:

    • accountUrl – 值應該是 Azure Cosmos DB 帳戶的 [金鑰] 刀鋒視窗中的 Azure Cosmos DB 帳戶 URL。
    • accountKey – 此值應該是 Azure Cosmos DB 帳戶 [金鑰] 刀鋒視窗中的 Azure Cosmos DB 主要金鑰(主要或次要金鑰)。
    • databaseId – 此值應該是 Azure Cosmos DB 資料庫的名稱。
    • collectionId – 此值應該是 Azure Cosmos DB 集合的名稱(在此案例中為 UserItems)。
    • hostUrl – 此值應該是來自 App Service 帳戶 [概觀] 刀鋒視窗的 Web 應用程式的 URL。

    下列螢幕快照示範此設定:

    App Service Web App Settings

  3. 將資源令牌代理程式解決方案發佈至 Azure App 服務 Web 應用程式。

Facebook 應用程式組態

建立 Facebook 應用程式以執行驗證的程式如下:

  1. 建立Facebook應用程式。 如需詳細資訊,請參閱 在Facebook開發人員中心註冊及設定應用程式
  2. 將 Facebook 登入產品新增至應用程式。 如需詳細資訊,請參閱 在Facebook開發人員中心將Facebook登入新增至您的應用程式或網站
  3. 設定 Facebook 登入,如下所示:
    • 啟用用戶端 OAuth 登入。
    • 啟用 Web OAuth 登入。
    • 將有效的 OAuth 重新導向 URI 設定為 App Service Web 應用程式的 URI,並 /.auth/login/facebook/callback 附加。

下列螢幕快照示範此設定:

Facebook Login OAuth Settings

如需詳細資訊,請參閱 向Facebook註冊您的應用程式。

Azure App 服務 驗證組態

設定 App Service 簡單驗證的程式如下:

  1. 在 Azure 入口網站中,流覽至 App Service Web 應用程式。

  2. 在 Azure 入口網站中,開啟 [驗證/授權] 刀鋒視窗,然後執行下列設定:

    • App Service 驗證應該開啟。
    • 未驗證要求時要採取的動作應該設定為 [使用Facebook登入]。

    下列螢幕快照示範此設定:

    App Service Web App Authentication Settings

App Service Web 應用程式也應該設定為與 Facebook 應用程式通訊,以啟用驗證流程。 選取 Facebook 身分識別提供者,並從 Facebook 開發人員中心的 Facebook 應用程式設定輸入 應用程式識別碼應用程式秘密 值,即可達成此目的。 如需詳細資訊,請參閱 將 Facebook 資訊新增至您的應用程式

Xamarin.Forms 應用程式組態

設定範例應用程式的程式 Xamarin.Forms 如下所示:

  1. Xamarin.Forms開啟方案。
  2. 開啟 Constants.cs 並更新下列常數的值:
    • EndpointUri – 值應該是 Azure Cosmos DB 帳戶的 [金鑰] 刀鋒視窗中的 Azure Cosmos DB 帳戶 URL。
    • DatabaseName – 值應該是文件資料庫的名稱。
    • CollectionName – 值應該是文件資料庫集合的名稱(在此案例中為 UserItems)。
    • ResourceTokenBrokerUrl – 此值應該是 App Service 帳戶 [概觀] 刀鋒視窗中資源令牌代理人 Web 應用程式的 URL。

起始登入

範例應用程式會藉由將瀏覽器重新導向至識別提供者 URL 來起始登入程式,如下列範例程式代碼所示:

var auth = new Xamarin.Auth.WebRedirectAuthenticator(
  new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/facebook"),
  new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/done"));

這會導致在 Azure App 服務 與 Facebook 之間起始 OAuth 驗證流程,以顯示 Facebook 登入頁面:

Facebook Login

您可以按下 iOS 上的 [取消 ] 按鈕或按下 Android 上的 [上一頁 ] 按鈕來取消登入,在此情況下,使用者仍未經驗證,且身分識別提供者使用者介面會從畫面中移除。

取得資源令牌

成功驗證之後, WebRedirectAuthenticator.Completed 就會引發 事件。 下列程式代碼範例示範處理此事件:

auth.Completed += async (sender, e) =>
{
  if (e.IsAuthenticated && e.Account.Properties.ContainsKey("token"))
  {
    var easyAuthResponseJson = JsonConvert.DeserializeObject<JObject>(e.Account.Properties["token"]);
    var easyAuthToken = easyAuthResponseJson.GetValue("authenticationToken").ToString();

    // Call the ResourceBroker to get the resource token
    using (var httpClient = new HttpClient())
    {
      httpClient.DefaultRequestHeaders.Add("x-zumo-auth", easyAuthToken);
      var response = await httpClient.GetAsync(Constants.ResourceTokenBrokerUrl + "/api/resourcetoken/");
      var jsonString = await response.Content.ReadAsStringAsync();
      var tokenJson = JsonConvert.DeserializeObject<JObject>(jsonString);
      resourceToken = tokenJson.GetValue("token").ToString();
      UserId = tokenJson.GetValue("userid").ToString();

      if (!string.IsNullOrWhiteSpace(resourceToken))
      {
        client = new DocumentClient(new Uri(Constants.EndpointUri), resourceToken);
        ...
      }
      ...
    }
  }
};

成功驗證的結果是存取令牌,這是可用的 AuthenticatorCompletedEventArgs.Account 屬性。 存取令牌會擷取並用於對資源令牌訊息代理程式 API 的 resourcetoken GET 要求中。

resourcetoken API 會使用存取令牌向 Facebook 要求使用者的身分識別,進而用來向 Azure Cosmos DB 要求資源令牌。 如果文件資料庫中的使用者已有有效的許可權檔存在,則會擷取,並傳回包含資源令牌的 Xamarin.Forms JSON 檔案給應用程式。 如果用戶沒有有效的許可權檔,則會在檔資料庫中建立使用者和許可權,而資源令牌會從許可權檔擷取,並傳回 JSON Xamarin.Forms 檔案中的應用程式。

注意

檔資料庫使用者是與文件資料庫相關聯的資源,而且每個資料庫可能包含零個或多個使用者。 檔資料庫許可權是與檔資料庫使用者相關聯的資源,而且每個使用者可能包含零個或多個許可權。 許可權資源提供用戶嘗試存取檔等資源時所需的安全性令牌存取權。

resourcetoken如果 API 成功完成,它會在回應中傳送 HTTP 狀態代碼 200 (確定),以及包含資源令牌的 JSON 檔。 下列 JSON 數據顯示典型的成功回應訊息:

{
  "id": "John Smithpermission",
  "token": "type=resource&ver=1&sig=zx6k2zzxqktzvuzuku4b7y==;a74aukk99qtwk8v5rxfrfz7ay7zzqfkbfkremrwtaapvavw2mrvia4umbi/7iiwkrrq+buqqrzkaq4pp15y6bki1u//zf7p9x/aefbvqvq3tjjqiffurfx+vexa1xarxkkv9rbua9ypfzr47xpp5vmxuvzbekkwq6txme0xxxbjhzaxbkvzaji+iru3xqjp05amvq1r1q2k+qrarurhmjzah/ha0evixazkve2xk1zu9u/jpyf1xrwbkxqpzebvqwma+hyyaazemr6qx9uz9be==;",
  "expires": 4035948,
  "userid": "John Smith"
}

WebRedirectAuthenticator.Completed事件處理程式會從 resourcetoken API 讀取回應,並擷取資源令牌和使用者識別碼。然後,資源令牌會當做自變數傳遞至DocumentClient建構函式,此建構函式會封裝用來存取 Azure Cosmos DB 的端點、認證和聯機原則,並用來設定和執行對 Azure Cosmos DB 的要求。 資源令牌會隨每個要求一起傳送,以直接存取資源,並指出已驗證使用者分割集合的讀取/寫入存取權已授與。

擷取檔

藉由建立包含使用者標識碼做為分割區索引鍵的文件查詢,即可擷取僅屬於已驗證用戶的檔,並在下列程式代碼範例中示範:

var query = client.CreateDocumentQuery<TodoItem>(collectionLink,
                        new FeedOptions
                        {
                          MaxItemCount = -1,
                          PartitionKey = new PartitionKey(UserId)
                        })
          .Where(item => !item.Id.Contains("permission"))
          .AsDocumentQuery();
while (query.HasMoreResults)
{
  Items.AddRange(await query.ExecuteNextAsync<TodoItem>());
}

查詢會以異步方式從指定的集合擷取屬於已驗證使用者的所有檔,並將其放在集合中 List<TodoItem> 以供顯示。

方法 CreateDocumentQuery<T> 會指定自 Uri 變數,代表應該查詢檔及 FeedOptions 物件的集合。 物件 FeedOptions 指定查詢可以傳回不限數目的專案,以及使用者的標識碼做為分割區索引鍵。 這可確保結果中只會傳回使用者分割集合中的檔。

注意

請注意,資源令牌代理程式所建立的許可權檔會儲存在與應用程式所建立檔相同的檔集合中 Xamarin.Forms 。 因此,文件查詢包含子 Where 句,這個子句會將篩選述詞套用至針對檔集合的查詢。 這個子句可確保不會從檔集合傳回許可權檔。

如需從檔集合中擷取檔的詳細資訊,請參閱 擷取檔集合檔

插入檔案

在將檔插入檔集合之前, TodoItem.UserId 應該使用做為分割區索引鍵的值來更新 屬性,如下列程式代碼範例所示:

item.UserId = UserId;
await client.CreateDocumentAsync(collectionLink, item);

這可確保檔會插入使用者的分割集合中。

如需將檔插入檔集合的詳細資訊,請參閱 將檔插入檔集合

刪除檔案

刪除分割區集合中的檔時,必須指定資料分割索引鍵值,如下列程式代碼範例所示:

await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName, Constants.CollectionName, id),
                 new RequestOptions
                 {
                   PartitionKey = new PartitionKey(UserId)
                 });

這可確保 Azure Cosmos DB 知道要從中刪除檔的分割集合。

如需從檔集合中刪除檔的詳細資訊,請參閱 從檔集合中刪除檔。

摘要

本文說明如何結合訪問控制與分割集合,讓使用者只能在應用程式中存取自己的檔資料庫檔 Xamarin.Forms 。 將使用者的身分識別指定為數據分割索引鍵可確保分割集合只能儲存該用戶的檔。