创建Stream Analytics作业时授权失败

时间:2015-07-17 08:51:13

标签: azure azure-stream-analytics

我一直在尝试(并且失败)以编程方式创建Azure Stream Analytics作业。我最初是在关注这个例子:

https://azure.microsoft.com/en-gb/documentation/articles/stream-analytics-dotnet-management-sdk/

但它会弹出一个对话框供您登录。我希望能够做到这个服务器端。看起来我需要使用Azure AD来使用Resource Manager API。我一直在努力解决这个问题:

https://msdn.microsoft.com/en-us/library/azure/dn790557.aspx#bk_portal

代码如下:

var authContext = new AuthenticationContext("https://login.microsoftonline.com/{tenant id}/oauth2/token");
var clientId = "{app client id}";
var appKey = "{app key}";
var subscriptionId = "{subscription id}";
var clientCredential = new ClientCredential(clientId, appKey);

var result = authContext.AcquireToken("https://management.core.windows.net/", clientCredential);
var creds = new TokenCloudCredentials(subscriptionId, result.AccessToken);

var client = new StreamAnalyticsManagementClient(creds);

var jobCreateParameters = new JobCreateOrUpdateParameters
        {
            Job = new Job
            {
                Name = streamAnalyticsJobName,
                Location = "North Europe",
                Properties = new JobProperties
                {
                    EventsOutOfOrderPolicy = EventsOutOfOrderPolicy.Adjust,
                    Sku = new Sku
                    {
                        Name = "Standard"
                    }
                }
            }
        };

 var jobCreateResponse = client.StreamingJobs.CreateOrUpdate(resourceGroupName, jobCreateParameters);

我可以成功获取令牌,但创建作业失败:

AuthorizationFailed: The client 'REDACTED' with object id 'REDACTED' does not have authorization to perform action 'Microsoft.StreamAnalytics/streamingjobs/write' over scope '/subscriptions/REDACTED/resourcegroups/REDACTED/providers/Microsoft.StreamAnalytics/streamingjobs/REDACTED'

我做错了吗?该应用已设置委派权限。

1 个答案:

答案 0 :(得分:4)

更新 - 2015年12月8日

现在可以轻松地将角色分配给服务主体。有关详细信息,请参阅此链接:https://azure.microsoft.com/en-in/documentation/articles/resource-group-create-service-principal-portal/

原始回复

当您向Azure订阅授予对应用程序的访问权限时,将在Azure AD中使用Service Principal用户类型创建用户。您在下面使用的代码假定您在获取访问令牌时使用此Service Principal用户。

var clientCredential = new ClientCredential(clientId, appKey);

var result = authContext.AcquireToken("https://management.core.windows.net/", clientCredential);
var creds = new TokenCloudCredentials(subscriptionId, result.AccessToken);

但是,默认情况下,此用户未获得您订阅的任何权限(RBAC),这就是您获得授权错误的原因。

要解决此问题,您需要做的是在订阅中为此用户授予适当的角色。现在您可以使用PowerShell来执行此操作,或者您可以使用ADAL库+发出一些Web请求通过代码执行此操作。

我做的是我使用ADAL库来获取访问令牌,然后使用Google Postman(或Fiddler)来做其他事情。就我而言,它是一个Web应用程序。这就是我的所作所为:

  1. 我以Global Administrator(订阅所有者)身份登录到应用程序并获得了code。使用code和ADAL库,我获得了访问令牌(让我们称之为token1)。

        var authContext = new AuthenticationContext(string.Format("{0}/common", signinEndpoint));//signinEndpoint = https://login.windows.net
        var result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, redirectUri, credential);
    
  2. 我复制了上面result返回给我的租户ID和访问令牌。

  3. 接下来我做的是使用POSTMAN找到Service Principal用户的对象ID。这是我在那里执行的GET URL。对于Authorization标头,您需要使用Bearer {token1}

    https://graph.windows.net/{subscription-id}/servicePrincipals?api-version=1.5&$filter=appId eq '{app-client-id}'

  4. 之后,我使用以下代码获取了另一个访问令牌(让我们称之为token2)以进行Service Management API操作:

    authContext = new AuthenticationContext(string.Format("{0}/{1}", signinEndpoint, result.TenantId));
    result = await authContext.AcquireTokenSilentAsync(serviceManagementApiEndpoint, credential, new UserIdentifier(request.UserInfo.UniqueId, UserIdentifierType.UniqueId));//serviceManagementApiEndpoint = https://management.core.windows.net/
    
  5. 之后,我在订阅中列出了角色,并选择了我想要分配给Service Principal用户的角色。在我的情况下,我想分配一个Reader角色,所以我记下了角色的ID。对于Authorization标头,您需要使用Bearer {token2}

    https://management.azure.com/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions?api-version=2015-06-01

  6. 接下来是将此角色分配给用户。为此我创建了一个guid role assignment id并使用以下URL:

    https://management.azure.com/subscriptions/{subscription-id}/providers/microsoft.authorization/roleassignments/{role-assignment-id}?api-version=2015-06-01

  7. 它将成为PUT请求,这就是请求正文:

    {
    "properties":
        {
            "roleDefinitionId": "{role id of the selected role from step 5}",
            "principalId": "{id of the service principal from step 3"
        }
    } 
    

    请确保请求的content-type设置为application/json;odata=verbose而不是application/json

    几乎就是这样!之后你的代码应该可以正常工作:)

    尝试一下,看看会发生什么。