Documentdb 简明教程

DocumentDB - Access Control

DocumentDB 提供了控制对 DocumentDB 资源的访问的概念。对 DocumentDB 资源的访问由主密钥令牌或资源令牌控制。基于资源令牌的连接只能访问令牌指定的资源,而不能访问其他资源。资源令牌基于用户权限。

  1. 首先,创建一到多个用户,并且这些用户在数据库级别上是经过定义的。

  2. 然后,为每个用户创建一到多个权限,具体取决于希望允许每个用户访问的资源。

  3. 每个权限都会生成一个资源令牌,该令牌允许仅读或完全访问某个资源,而该资源可以是数据库中的任何用户资源。

  4. 用户在数据库级别上进行定义,权限针对每个用户进行定义。

  5. 用户和权限应用于数据库中的所有集合。

我们来看一个简单的示例,在这个示例中,我们将了解如何定义用户和权限,以实现在 DocumentDB 中的细粒度安全。

从一个新的 DocumentClient 开始,查询 myfirstdb 数据库。

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
         'myfirstdb'").AsEnumerable().First();

      collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
         "SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();

      var alice = await CreateUser(client, "Alice");
      var tom = await CreateUser(client, "Tom");
   }
}

下面是 CreateUser 的实现。

private async static Task<User> CreateUser(DocumentClient client, string userId) {
   Console.WriteLine();
   Console.WriteLine("**** Create User {0} in {1} ****", userId, database.Id);

   var userDefinition = new User { Id = userId };
   var result = await client.CreateUserAsync(database.SelfLink, userDefinition);
   var user = result.Resource;

   Console.WriteLine("Created new user");
   ViewUser(user);

   return user;
}

Step 1 −创建两个用户 Alice 和 Tom,就像我们创建的任何资源一样。根据所需的 ID 构建一个定义对象,然后调用 create 方法;在该示例中,我们正在调用 CreateUserAsync 以及数据库的 SelfLink 和 userDefinition。我们从新创建的用户对象的 resource 属性中获取返回的结果。

现在查看数据库中的这两个新用户。

private static void ViewUsers(DocumentClient client) {
   Console.WriteLine();
   Console.WriteLine("**** View Users in {0} ****", database.Id);

   var users = client.CreateUserQuery(database.UsersLink).ToList();
   var i = 0;

   foreach (var user in users) {
      i++;
      Console.WriteLine();
      Console.WriteLine("User #{0}", i);
      ViewUser(user);
   }

   Console.WriteLine();
   Console.WriteLine("Total users in database {0}: {1}", database.Id, users.Count);
}

private static void ViewUser(User user) {
   Console.WriteLine("User ID: {0} ", user.Id);
   Console.WriteLine("Resource ID: {0} ", user.ResourceId);
   Console.WriteLine("Self Link: {0} ", user.SelfLink);
   Console.WriteLine("Permissions Link: {0} ", user.PermissionsLink);
   Console.WriteLine("Timestamp: {0} ", user.Timestamp);
}

Step 2 −针对数据库的 UsersLink 调用 CreateUserQuery,以检索所有用户的列表。然后遍历这些用户并查看它们的属性。

现在我们必须首先创建它们。所以假设我们想要允许 Alice 对 MyCollection 集合进行读/写,而 Tom 只可以读取集合中的文档。

await CreatePermission(client, alice, "Alice Collection Access", PermissionMode.All,
   collection);

await CreatePermission(client, tom, "Tom Collection Access", PermissionMode.Read,
   collection);

Step 3 −在一个资源(MyCollection 集合)上创建权限,因此我们需要获得该资源的 SelfLink。

Step 4 −然后为 Alice 创建这个集合的 Permission.All,为 Tom 创建这个集合的 Permission.Read。

以下是 CreatePermission 的实现。

private async static Task CreatePermission(DocumentClient client, User user,
   string permId, PermissionMode permissionMode, string resourceLink) {
   Console.WriteLine();
   Console.WriteLine("**** Create Permission {0} for {1} ****", permId, user.Id);

   var permDefinition = new Permission {
      Id = permId,
      PermissionMode = permissionMode,
      ResourceLink = resourceLink
   };

   var result = await client.CreatePermissionAsync(user.SelfLink, permDefinition);
   var perm = result.Resource;
   Console.WriteLine("Created new permission");
   ViewPermission(perm);
}

正如你预期的那样,我们通过创建一个新的权限的定义对象来实现此操作,其中包括一个 Id 和一个权限模式,它可能是 Permission.All 或 Permission.Read,以及要通过该权限保护的资源的 SelfLink。

@ {s0} − 调用 CreatePermissionAsync 并从结果中的 resource 属性获取已创建的权限。

要查看创建的权限,以下是 ViewPermissions 的实现。

private static void ViewPermissions(DocumentClient client, User user) {
   Console.WriteLine();
   Console.WriteLine("**** View Permissions for {0} ****", user.Id);

   var perms = client.CreatePermissionQuery(user.PermissionsLink).ToList();
   var i = 0;

   foreach (var perm in perms) {
      i++;
      Console.WriteLine();
      Console.WriteLine("Permission #{0}", i);
      ViewPermission(perm);
   }

   Console.WriteLine();
   Console.WriteLine("Total permissions for {0}: {1}", user.Id, perms.Count);
}

private static void ViewPermission(Permission perm) {
   Console.WriteLine("Permission ID: {0} ", perm.Id);
   Console.WriteLine("Resource ID: {0} ", perm.ResourceId);
   Console.WriteLine("Permission Mode: {0} ", perm.PermissionMode);
   Console.WriteLine("Token: {0} ", perm.Token);
   Console.WriteLine("Timestamp: {0} ", perm.Timestamp);
}

这次,它对用户的权限链接进行权限查询,我们只需列出为用户返回的每个权限。

让我们删除 Alice 和 Tom 的权限。

await DeletePermission(client, alice, "Alice Collection Access");
await DeletePermission(client, tom, "Tom Collection Access");

以下是 DeletePermission 的实现。

private async static Task DeletePermission(DocumentClient client, User user,
   string permId) {
   Console.WriteLine();
   Console.WriteLine("**** Delete Permission {0} from {1} ****", permId, user.Id);

   var query = new SqlQuerySpec {
      QueryText = "SELECT * FROM c WHERE c.id = @id",
      Parameters = new SqlParameterCollection {
         new SqlParameter { Name = "@id", Value = permId }
      }
   };

   Permission perm = client.CreatePermissionQuery(user.PermissionsLink, query)
      .AsEnumerable().First();
   await client.DeletePermissionAsync(perm.SelfLink);
   Console.WriteLine("Deleted permission {0} from user {1}", permId, user.Id);
}

@ {s1} − 为了删除权限,按权限 Id 查询以获取 SelfLink,然后使用 SelfLink 删除权限。

接下来,让我们删除用户本人。我们删除这两个用户。

await DeleteUser(client, "Alice");
await DeleteUser(client, "Tom");

以下是 DeleteUser 的实现。

private async static Task DeleteUser(DocumentClient client, string userId) {
   Console.WriteLine();
   Console.WriteLine("**** Delete User {0} in {1} ****", userId, database.Id);

   var query = new SqlQuerySpec {
      QueryText = "SELECT * FROM c WHERE c.id = @id",
      Parameters = new SqlParameterCollection {
         new SqlParameter { Name = "@id", Value = userId }
      }
   };

   User user = client.CreateUserQuery(database.SelfLink, query).AsEnumerable().First();
   await client.DeleteUserAsync(user.SelfLink);
   Console.WriteLine("Deleted user {0} from database {1}", userId, database.Id);
}

@ {s2} − 首先查询以获取她的 SelfLink,然后调用 DeleteUserAsync 以删除她的用户对象。

以下是 CreateDocumentClient 任务的实现,其中我们调用了上述所有任务。

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
         'myfirstdb'").AsEnumerable().First();

      collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
         "SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();

      ViewUsers(client);

      var alice = await CreateUser(client, "Alice");
      var tom = await CreateUser(client, "Tom");
      ViewUsers(client);

      ViewPermissions(client, alice);
      ViewPermissions(client, tom);

      string collectionLink = client.CreateDocumentCollectionQuery(database.SelfLink,
         "SELECT VALUE c._self FROM c WHERE c.id = 'MyCollection'")
         .AsEnumerable().First().Value;

      await CreatePermission(client, alice, "Alice Collection Access", PermissionMode.All,
         collectionLink);

      await CreatePermission(client, tom, "Tom Collection Access", PermissionMode.Read,
         collectionLink);

      ViewPermissions(client, alice);
      ViewPermissions(client, tom);

      await DeletePermission(client, alice, "Alice Collection Access");
      await DeletePermission(client, tom, "Tom Collection Access");

      await DeleteUser(client, "Alice");
      await DeleteUser(client, "Tom");
   }
}

当以上代码编译并执行时,您将收到以下输出。

**** View Users in myfirstdb ****

Total users in database myfirstdb: 0

**** Create User Alice in myfirstdb ****
Created new user
          User ID: Alice
      Resource ID: kV5oAC56NwA=
        Self Link: dbs/kV5oAA==/users/kV5oAC56NwA=/
 Permissions Link: dbs/kV5oAA==/users/kV5oAC56NwA=/permissions/
        Timestamp: 12/17/2015 5:44:19 PM

**** Create User Tom in myfirstdb ****
Created new user
          User ID: Tom
      Resource ID: kV5oAALxKgA=
        Self Link: dbs/kV5oAA==/users/kV5oAALxKgA=/
 Permissions Link: dbs/kV5oAA==/users/kV5oAALxKgA=/permissions/
        Timestamp: 12/17/2015 5:44:21 PM

**** View Users in myfirstdb ****

User #1
          User ID: Tom
      Resource ID: kV5oAALxKgA=
        Self Link: dbs/kV5oAA==/users/kV5oAALxKgA=/
 Permissions Link: dbs/kV5oAA==/users/kV5oAALxKgA=/permissions/
        Timestamp: 12/17/2015 5:44:21 PM

User #2
          User ID: Alice
      Resource ID: kV5oAC56NwA=
        Self Link: dbs/kV5oAA==/users/kV5oAC56NwA=/
 Permissions Link: dbs/kV5oAA==/users/kV5oAC56NwA=/permissions/
        Timestamp: 12/17/2015 5:44:19 PM

Total users in database myfirstdb: 2

**** View Permissions for Alice ****

Total permissions for Alice: 0

**** View Permissions for Tom ****

Total permissions for Tom: 0

**** Create Permission Alice Collection Access for Alice ****
Created new permission
    Permission ID: Alice Collection Access
      Resource ID: kV5oAC56NwDON1RduEoCAA==
  Permission Mode: All
            Token: type=resource&ver=1&sig=zB6hfvvleC0oGGbq5cc67w==;Zt3Lx
Ol14h8pd6/tyF1h62zbZKk9VwEIATIldw4ZyipQGW951kirueAKdeb3MxzQ7eCvDfvp7Y/ZxFpnip/D G
JYcPyim5cf+dgLvos6fUuiKSFSul7uEKqp5JmJqUCyAvD7w+qt1Qr1PmrJDyAIgbZDBFWGe2VT9FaBH o
PYwrLjRlnH0AxfbrR+T/UpWMSSHtLB8JvNFZNSH8hRjmQupuTSxCTYEC89bZ/pS6fNmNg8=;
        Timestamp: 12/17/2015 5:44:28 PM

**** Create Permission Tom Collection Access for Tom ****
Created new permission
    Permission ID: Tom Collection Access
      Resource ID: kV5oAALxKgCMai3JKWdfAA==
  Permission Mode: Read
            Token: type=resource&ver=1&sig=ieBHKeyi6EY9ZOovDpe76w==;92gwq
V4AxKaCJ2dLS02VnJiig/5AEbPcfo1xvOjR10uK3a3FUMFULgsaK8nzxdz6hLVCIKUj6hvMOTOSN8Lt 7
i30mVqzpzCfe7JO3TYSJEI9D0/5HbMIEgaNJiCu0JPPwsjVecTytiLN56FHPguoQZ7WmUAhVTA0IMP6 p
jQpLDgJ43ZaG4Zv3qWJiO689balD+egwiU2b7RICH4j6R66UVye+GPxq/gjzqbHwx79t54=;
        Timestamp: 12/17/2015 5:44:30 PM

**** View Permissions for Alice ****

Permission #1
    Permission ID: Alice Collection Access
      Resource ID: kV5oAC56NwDON1RduEoCAA==
  Permission Mode: All
            Token: type=resource&ver=1&sig=BSzz/VNe9j4IPJ9M31Mf4Q==;Tcq/B
X50njB1vmANZ/4aHj/3xNkghaqh1OfV95JMi6j4v7fkU+gyWe3mJasO3MJcoop9ixmVnB+RKOhFaSxE l
P37SaGuIIik7GAWS+dcEBWglMefc95L2YkeNuZsjmmW5b+a8ELCUg7N45MKbpzkp5BrmmGVJ7h4Z4pf D
rdmehYLuxSPLkr9ndbOOrD8E3bux6TgXCsgYQscpIlJHSKCKHUHfXWBP2Y1LV2zpJmRjis=;
        Timestamp: 12/17/2015 5:44:28 PM

Total permissions for Alice: 1

**** View Permissions for Tom ****
Permission #1
    Permission ID: Tom Collection Access
      Resource ID: kV5oAALxKgCMai3JKWdfAA==
  Permission Mode: Read
            Token: type=resource&ver=1&sig=NPkWNJp1mAkCASE8KdR6PA==;ur/G2
V+fDamBmzECux000VnF5i28f8WRbPwEPxD1DMpFPqYcu45wlDyzT5A5gBr3/R3qqYkEVn8bU+een6Gl j
L6vXzIwsZfL12u/1hW4mJT2as2PWH3eadry6Q/zRXHAxV8m+YuxSzlZPjBFyJ4Oi30mrTXbBAEafZhA 5
yvbHkpLmQkLCERy40FbIFOzG87ypljREpwWTKC/z8RSrsjITjAlfD/hVDoOyNJwX3HRaz4=;
        Timestamp: 12/17/2015 5:44:30 PM

Total permissions for Tom: 1

**** Delete Permission Alice Collection Access from Alice ****
Deleted permission Alice Collection Access from user Alice

**** Delete Permission Tom Collection Access from Tom ****
Deleted permission Tom Collection Access from user Tom

**** Delete User Alice in myfirstdb ****
Deleted user Alice from database myfirstdb

**** Delete User Tom in myfirstdb ****
Deleted user Tom from database myfirstdb