3

我有一个受 Azure AD 身份验证保护的 Azure Function App(HTTP 触发函数)。

这工作正常 - 当我在浏览器中转到函数的 URL 时。我首先被重定向到登录页面,我可以使用我的 Azure Active Directory 登录凭据登录。

但是,我希望该函数连接到 Dynamics 365 Web API 以使用登录用户的身份读取一些数据。关于连接到 Web API 和在 Azure 中配置应用程序权限的代码,我已经复制了这个示例。我的 Dynamics 365 实例与我的 Azure 和我正在使用有权访问 Dynamics 365 的用户登录的用户位于同一租户中。

我正在努力的部分是获取访问令牌以调用与登录用户相对应的 Dynamics Web API。

第一次尝试

然后,我尝试根据“X-MS-TOKEN-AAD-ID-TOKEN”标头使用当前登录用户的令牌。我的代码如下 - 它没有连接到 Dynamics Web API - 我得到 401 - Unauthorized 响应:

[FunctionName("TestCrmFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
    var crmUrl = "https://myorganisation.crm11.dynamics.com";

    // Get the token from the HTTP header of the request:
    var token = req.Headers
        .Where(x => x.Key == "X-MS-TOKEN-AAD-ID-TOKEN")
        .SelectMany(x => x.Value)
        .FirstOrDefault();

    using (var httpClient = new HttpClient())
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

        httpClient.BaseAddress = new Uri(crmUrl);

        // set the token here:
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var response = await httpClient.GetAsync("api/data/v8.1/WhoAmI");

        var content = await response.Content.ReadAsStringAsync();

        if (response.IsSuccessStatusCode)
        {
            // I don't get here...
            return req.CreateResponse(HttpStatusCode.OK, content);
        }
        else
        {
            // ... I get here
            return req.CreateResponse(response.StatusCode, $"ERROR: {content}");
        }
    }

}

似乎“X-MS-TOKEN-AAD-ID-TOKEN”没有被接受。

第二次尝试

我试图通过创建一个“UserAssertion”实例以及一个 ClientCredential 来为用户获取一个新令牌。UserAssertion 位我真的不确定并且可能是错误的:

var tenantId = "<my organisation tenantID>";
var authority = $"https://login.microsoftonline.com/{tenantId}";
var authenticationContext = new AuthenticationContext(authority, false);

// create the client credential using the clientID and clientSecret:
var clientId = "<my applicationId>";
var clientSecret = "<key for my application>";
var clientCredential = new ClientCredential(clientId, clientSecret);

// create the user assertion using the access token from the authenticated user:
var accessToken = req.Headers
    .Where(x => x.Key == "X-MS-TOKEN-AAD-ACCESS-TOKEN")
    .SelectMany(x => x.Value)
    .FirstOrDefault();

var userAssertion = new UserAssertion(
    accessToken,
    "urn:ietf:params:oauth:grant-type:jwt-bearer",
    ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn)?.Value);

// get a new token - this step is failing
var crmUrl = "https://myorganisation.crm11.dynamics.com";
AuthenticationResult authenticationResult = 
    await authenticationContext.AcquireTokenAsync(crmUrl, clientCredential, userAssertion);

string token = authenticationResult.AccessToken;

我得到的回应是

Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.

解决方法 - 不是真正的解决方案

我设法开始工作的唯一一件事是硬编码我正在登录的用户的用户名/密码:

var credentials = new UserPasswordCredential("<my username>", "<my password>");

AuthenticationResult authenticationResult = await 
authenticationContext.AcquireTokenAsync(crmUrl, clientId, credentials);

...但是这种失败的目的 - 通过硬编码用户名/密码,我肯定只是完全绕过 Azure 应用程序注册安全性?

4

2 回答 2

0

通过连接 Azure Function App 并为其提供安全凭据以连接到 Dynamics 365、检索数据、执行一些数据操作,然后将数据写回 Dynamics 365,我确实做了同样的事情。

请参阅下面我的帖子,如果对您的情况有所帮助,希望您可以将其标记为已回答。

验证 Azure Function App 以在线连接到 Dynamics 365 CRM

于 2018-06-27T09:56:37.470 回答
0

这更像是一种替代方案,但可能更容易实现。

如果您能够以某种方式识别当前用户,例如从令牌中读取详细信息。然后您可以使用服务帐户连接到 CRM,但将服务对象设置为模拟用户。

冒充其他用户

模拟用户

要模拟用户,请在调用服务的 Web 方法之前在 OrganizationServiceProxy 的实例上设置 CallerId 属性。

// Retrieve the system user ID of the user to impersonate.
OrganizationServiceContext orgContext = new OrganizationServiceContext(_serviceProxy);
_userId = (from user in orgContext.CreateQuery<SystemUser>()
          where user.FullName == "Something from your token" //perhaps domain name?
          select user.SystemUserId.Value).FirstOrDefault();

// To impersonate another user, set the OrganizationServiceProxy.CallerId
// property to the ID of the other user.
_serviceProxy.CallerId = _userId;
于 2018-06-20T20:16:20.953 回答