I'm trying to connect to my cosmos db
database by using a Resource token
instead of a account master key
which I used before. Before I used the following way to create DocumentClient
:
var client = new DocumentClient(new Uri(configAccountName), configAccountKey);
await client.OpenAsync();
This way works well, but I want to use resource token
ways for that target as mentioned in these articles : link1 and link2 .
I've created a db user
with All permissions
by the following code:
public static async Task<User> CreateUserAndPermissionAsync(this DocumentClient client, string userId)
{
var dbUri = UriFactory.CreateDatabaseUri(dataBase);
var user = await client.CreateUserAsync(dbUri, new User { Id = userId });
var collectionUri = UriFactory.CreateDocumentCollectionUri(dataBase, collectionName);
var permission = await client.CreatePermissionAsync(
user.Resource.SelfLink,
new Permission
{
Id = "MyPermission",
PermissionMode = PermissionMode.All,
ResourceLink = collectionUri.ToString(),
ResourcePartitionKey = new PartitionKey(userId)
});
return user.Resource;
}
The user is created correctly and I can retrieve him by ReadUserAsync
or his permissions by ReadPermissionAsync
methods. Then, I want to create new instance of DocumentClient
with permissions
of newly created user.
//this is a temporally document client instance to read permissions for my user in below extensions method versions
var client = new DocumentClient(new Uri(configAccountName), configAccountKey);
I've checked 3 ways (some of them are similar). I've tryied to call each of ways to get new DocumentClient
instance( newClient variable) and then call OpenAsync
method to open connection:
var newClient = await client.GetClientForUserAsync_v###(userName);
await newClient.OpenAsync();
All tryings were failed
//version 1:
public static async Task<DocumentClient> GetClientForUserAsync_v1(this DocumentClient client, string userId)
{
var userUri = UriFactory.CreateUserUri(dataBase, userId).ToString();
var permissionsUri = $"{userUri}/permissions";
var permissions = (await client.ReadPermissionFeedAsync(permissionsUri)).ToList();
return new DocumentClient(
client.ServiceEndpoint,
permissions,
client.ConnectionPolicy);
}
The OpenAsync
method was crashed with this error : Failed to parse the value '' as ResourceId., documentdb-dotnet-sdk/1.22.0 Host/32-bit MicrosoftWindowsNT/6.2.9200.0
//version 2:
public static async Task<DocumentClient> GetClientForUserAsync_v2(this DocumentClient client, string userId)
{
var userUri = UriFactory.CreateUserUri(dataBase, userId).ToString();
var permissionsUri = $"{userUri}/permissions";
var permissions = (await client.ReadPermissionFeedAsync(permissionsUri)).ToList();
return new DocumentClient(
client.ServiceEndpoint,
permissions[0].Token,
client.ConnectionPolicy);
}
The OpenAsync
method was crashed with this error : Insufficient permissions provided in the authorization header for the corresponding request. Please retry with another authorization header. ActivityId: ##ReplacedActivityId##, Microsoft.Azure.Documents.Common/1.22.0.0, documentdb-dotnet-sdk/1.22.0 Host/32-bit MicrosoftWindowsNT/6.2.9200.0
//version 3:
public static async Task<DocumentClient> GetClientForUserAsync_v3(this DocumentClient client, string userId)
{
FeedResponse<Permission> permFeed = await client.ReadPermissionFeedAsync(UriFactory.CreateUserUri(dataBase, userId));
List<Permission> permList = new List<Permission>();
foreach (Permission perm in permFeed)
{
permList.Add(perm);
}
DocumentClient userClient = new DocumentClient(new Uri(client.ServiceEndpoint.AbsoluteUri), permList, new ConnectionPolicy()
{
//**UPDATE**: I tried all ConnectionMode values as well as without this parameter
ConnectionMode = ConnectionMode.Gateway
});
return userClient;
}
The OpenAsync
method was crashed with this error : Failed to parse the value '' as ResourceId., documentdb-dotnet-sdk/1.22.0 Host/32-bit MicrosoftWindowsNT/6.2.9200.0 .
The first and third errors are the most strange, because I've checked and I see the ResourceId
value in the perm variable (as item of permList collection) as well as in permissions variable from the first version.
Could anyone help with it?
UPDATE I've checked the 4th version, which gives me the same result as 1,3 trying: Failed to parse the value '' as ResourceId., documentdb-dotnet-sdk/1.22.0 Host/32-bit MicrosoftWindowsNT/6.2.9200.0
//version 4
public static async Task<DocumentClient> GetClientForUserAsync_v4(this DocumentClient client, string userId)
{
var user = await client.ReadUserAsync(UriFactory.CreateUserUri(dataBase, userId));
var permissions = await client.ReadPermissionFeedAsync(user.Resource.SelfLink);
List<Permission> permList = new List<Permission>();
foreach (Permission perm in permissions)
{
permList.Add(perm);
}
DocumentClient userClient = new DocumentClient(new Uri(client.ServiceEndpoint.AbsoluteUri), permList, new ConnectionPolicy()
{
ConnectionMode = ConnectionMode.Direct
});
return userClient;
}
The Cosmos DB resource token will be generated when the permission been built. We can use resource token to connect to Cosmos DB like below:
var client = new DocumentClient(new Uri(endPointUri), resourceToken );
And we can get resource Token of the permission as below:
public static async Task<Dictionary<PermissionMode, string>> GetPermissonTokens(DocumentClient client,string DatabaseId,string userId)
{
FeedResponse<Permission> permFeed = await client.ReadPermissionFeedAsync(UriFactory.CreateUserUri(DatabaseId, userId));
Dictionary<PermissionMode,string> permList = new Dictionary<PermissionMode, string>();
foreach (Permission perm in permFeed)
{
permList.Add(perm.PermissionMode, perm.Token);
}
return permList;
}
Here is a Complete demo for your reference:
static void Main(string[] args)
{
//create DocumentClient instance with end point Uri and primary key
DocumentClient client = new DocumentClient(new Uri("https://xxxx.xxxxx.azure.com:443/"), "ikhSrMZIGKBrF1xxxxx7iDSLBMJD37oCOlw2N24YoBtfAV7HJFfVgNbhCfQdWGAq3eZY4FyX3z6zsWoRLHQ==", new ConnectionPolicy { EnableEndpointDiscovery = false });
Task<Dictionary<PermissionMode, string>> task = GetPermissonTokens(client, "Test2", "testUser2");
task.Wait();
Dictionary<PermissionMode, string> permissionTokens = task.Result;
DocumentClient userClient = new DocumentClient(client.ReadEndpoint, permissionTokens[PermissionMode.All]);
if (userClient != null)
{
//then we can do CRUD operation to Cosmos DB Here
}
}
public static async Task<Dictionary<PermissionMode, string>> GetPermissonTokens(DocumentClient client,string DatabaseId,string userId)
{
FeedResponse<Permission> permFeed = await client.ReadPermissionFeedAsync(UriFactory.CreateUserUri(DatabaseId, userId));
Dictionary<PermissionMode,string> permList = new Dictionary<PermissionMode, string>();
foreach (Permission perm in permFeed)
{
permList.Add(perm.PermissionMode, perm.Token);
}
return permList;
}
I have similar case where in my model I am using partitioning. So, I have developed this function to be get the user token.
private async Task<string> GetUserToken()
{
User user = null;
try
{
try
{
var uri = UriFactory.CreateUserUri(config.Database, config.PartitionKey);
client.DeleteUserAsync(uri).Wait();
user = await client.ReadUserAsync(UriFactory.CreateUserUri(config.Database, config.PartitionKey));
var permission = await GetorCreatePermission(user, config.Collection, config.PartitionKey);
return permission.Token;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
if (user == null)
{
user = new User
{
Id = config.PartitionKey
};
user = await client.CreateUserAsync(UriFactory.CreateDatabaseUri(config.Database), user);
var permission = await GetorCreatePermission(user, config.Collection, config.PartitionKey);
return permission.Token;
}
else
{
throw new Exception("");
}
}
catch (Exception ex)
{
throw ex;
}
}
After multiple attempts, the one conclusion I ended up was not to include the PartitionKey when creating permission for the collection. The below tweak did the job for me and I am able to successfully add contents to my collection using resource tokens.
new Permission
{
Id = "MyPermission",
PermissionMode = PermissionMode.All,
ResourceLink = collectionUri.ToString()
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.