不弹出框的情况下使用C# ADAL AcquireTokenAsync()函数

7
我们正在编写一个WCF服务,需要与Dynamics CRM 2016在线集成。我们试图使用ADAL进行身份验证, 并使用AcquireTokenAsync()方法。问题是,它会显示一个弹出框,提示用户输入凭据。显然,我们的应用程序是一个服务,不需要这样做。我们一直在寻找一种不需要该弹出窗口即可进行身份验证的方法。
有一个名为AuthenticationContextIntegratedAuthExtensions的类,它被认为可以协助进行“用户名/密码流”身份验证。它只有一个方法AcquireTokenAsync,可以抑制弹出窗口,但我们没有找到任何传递密码的方法。当仅使用用户名运行时,它会引发异常,基本上就是“未提供密码”。
有人有解决此问题的想法吗?甚至不需要ADAL,只需要获取OAuth令牌的方法。
3个回答

4
private static string API_BASE_URL = "https://<CRM DOMAIN>.com/";
private static string API_URL = "https://<CRM DOMAIN>.com/api/data/v8.1/";
private static string CLIENT_ID = "<CLIENT ID>";

static void Main(string[] args)
{
    var ap = AuthenticationParameters.CreateFromResourceUrlAsync(
                new Uri(API_URL)).Result;

    var authContext = new AuthenticationContext(ap.Authority, false);

    var userCredential = new UserCredential("<USERNAME>", "<PASSWORD>");

    var result = authContext.AcquireToken(API_BASE_URL, CLIENT_ID, userCredential);

    var httpClient = HttpWebRequest.CreateHttp(Path.Combine(API_URL, "accounts"));
    httpClient.Headers.Add(HttpRequestHeader.Authorization, "Bearer:" + result.AccessToken);
    using (var sr = new StreamReader(httpClient.GetResponse().GetResponseStream()))
    {
        Console.WriteLine(sr.ReadToEnd());
    }
}

注意:我正在使用较旧的ADAL版本(2.19.208020213),因为似乎已从UserCredential构造函数中删除了密码参数。
编辑:最新版本的ADAL有UserPasswordCredential,可以替代UserCredential(并且可能是在从UserCredential中删除Password后立即添加的)。
编辑2:CRM现在支持服务器到服务器身份验证,允许您创建应用程序用户。

是的。密码字段因某种原因被移除了。事实上,我们没有找到任何与密码相关的类或方法。一些类具有构造函数,接受用户名、用户标识符等参数,但它们似乎只是用于自动完成而非尝试进行安静的身份验证。 - eltaro
对的,我也不确定为什么它被移除了(这篇博客http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/是我最初阅读时记得的),但如果你使用上面指定的版本,你可以在没有弹出窗口的情况下进行身份验证,并且令牌将适用于针对CRM的请求。 - Matt Dearing
看起来我们将不得不使用你的解决方案。我在这里贴的那个解决方案无法让我们访问CRM,会出现401错误。 - eltaro

1
"不使用ADAL,这可能有所帮助。"
var postData = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("resource", cred.ResourceId),
            new KeyValuePair<string, string>("grant_type", "client_credentials"),
            new KeyValuePair<string, string>("client_id", cred.ClientId),
            new KeyValuePair<string, string>("client_secret", cred.ClientSecret),

        };

        using (var client = new HttpClient()) {

            string baseUrl = "https://login.windows.net/YourAADInstanceName.onmicrosoft.com/oauth2/";
            client.BaseAddress = new Uri(baseUrl);                
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            var content = new FormUrlEncodedContent(postData);

            HttpResponseMessage response = await client.PostAsync("token", content);               
            string jsonString = await response.Content.ReadAsStringAsync();                
            var responseData = JsonConvert.DeserializeObject<Token>(jsonString);
            return responseData;
        }

这个程序进行身份验证并返回一个accessToken,但是当我使用该token时,它会返回401错误。 - Justin

0

好的,最终找到了解决方案。

如果您已经在Azure AD中注册应用程序(作为Web App / Web API而不是本机应用程序),则会收到该应用程序的客户端ID和秘密密钥。

以下是获取令牌而无需弹出窗口的代码:

AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(
                        new Uri(resource+"/api/data/v8.1")).Result;

AuthenticationContext ac = new AuthenticationContext(ap.Authority);

AuthenticationResult r = await ac.AcquireTokenAsync(ap.Resource, new ClientCredential(clientId,clientSecret));

resource 是您 Dynamics CRM 部署的基本 URL。

身份验证参数是在运行时发现的,建议参考此 MSDN 文章


你尝试使用这个令牌对CRM的WebAPI进行调用了吗?如果没有指定用户,我很好奇你拥有的令牌是否能够在传递给CRM时正常工作。如果它确实有效,那么在CRM中是以谁的身份进行调用的呢? - Matt Dearing
1
目前还没有。但是,当您在Azure AD中注册应用程序时,可以授予其对Dynamics CRM的权限。并不是特定的CRM,所以我认为您可以访问部署在该Azure AD上的任何实例。而AuthenticationParameters是通过ping我们的CRM实例获取的,然后我们使用它来通过将AuthenticationParameters.Resource传递给AcquireTokenAsync()来对基础AD进行身份验证。 - eltaro
但是您没有通过身份验证,CRM允许“委派权限”而不是“应用程序权限”,这意味着您需要一个已登录的用户。当您将此令牌提供给CRM时,您可能会收到401错误。 - Matt Dearing
是的,未经身份验证为特定用户。我今天将编写一些针对CRM的查询,并查看它是否会抱怨此问题。 - eltaro
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - eltaro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接