C# ADAL AcquireTokenAsync() 无弹出框
C# ADAL AcquireTokenAsync() without pop-up box
我们正在编写一个必须与 Dynamics CRM 2016 Online 集成的 WCF 服务。我正在尝试使用方法 AcquireTokenAsync()
使用 ADAL 进行身份验证。问题是,它会显示一个弹出框,提示用户输入凭据。自然地,我们的应用程序是一种服务,这不是我们想要的。我们一直在寻找一种无需此弹出框即可进行身份验证的方法。
有一个名为 AuthenticationContextIntegratedAuthExtensions
的 class,应该可以协助 "username/password flow"。它有单一的方法AcquireTokenAsync
,可以抑制弹出框,但是我们还没有找到任何方法可以将密码传递给它。当 运行 仅包含用户名时,它引发的异常基本上是 "no password was supplied".
有人知道如何解决这个问题吗?甚至不必是 ADAL。只是获取 OAuth 令牌的东西。
好的,最终找到了解决方案。
如果您已使用 Azure AD 注册您的应用程序(作为 Web 应用程序/Web API,而不是本机应用程序),您将收到该应用程序的客户端 ID 和密钥。
无弹窗获取token的代码window如下:
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));
资源是 Dynamics CRM 部署的基础 URL。
按照此 MSDN acticle 中的建议,在 运行 时间发现身份验证参数。
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
(并且可能在 Password
已从 UserCredential
)
中删除
编辑 2: CRM 现在支持 Server to Server Authentication,允许您创建应用程序用户。
不使用 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;
}
我们正在编写一个必须与 Dynamics CRM 2016 Online 集成的 WCF 服务。我正在尝试使用方法 AcquireTokenAsync()
使用 ADAL 进行身份验证。问题是,它会显示一个弹出框,提示用户输入凭据。自然地,我们的应用程序是一种服务,这不是我们想要的。我们一直在寻找一种无需此弹出框即可进行身份验证的方法。
有一个名为 AuthenticationContextIntegratedAuthExtensions
的 class,应该可以协助 "username/password flow"。它有单一的方法AcquireTokenAsync
,可以抑制弹出框,但是我们还没有找到任何方法可以将密码传递给它。当 运行 仅包含用户名时,它引发的异常基本上是 "no password was supplied".
有人知道如何解决这个问题吗?甚至不必是 ADAL。只是获取 OAuth 令牌的东西。
好的,最终找到了解决方案。
如果您已使用 Azure AD 注册您的应用程序(作为 Web 应用程序/Web API,而不是本机应用程序),您将收到该应用程序的客户端 ID 和密钥。
无弹窗获取token的代码window如下:
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));
资源是 Dynamics CRM 部署的基础 URL。
按照此 MSDN acticle 中的建议,在 运行 时间发现身份验证参数。
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
(并且可能在 Password
已从 UserCredential
)
编辑 2: CRM 现在支持 Server to Server Authentication,允许您创建应用程序用户。
不使用 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;
}