Dynamics crm Dynamics Web API-刷新令牌
我正在使用Dynamics Web API和Microsoft.IdentifyModel.Clients.ActiveDirectory包从Azure函数(.NET Core)应用程序连接到Dynamics 我的连接相当标准Dynamics crm Dynamics Web API-刷新令牌,dynamics-crm,microsoft-dynamics,dynamics-crm-webapi,Dynamics Crm,Microsoft Dynamics,Dynamics Crm Webapi,我正在使用Dynamics Web API和Microsoft.IdentifyModel.Clients.ActiveDirectory包从Azure函数(.NET Core)应用程序连接到Dynamics 我的连接相当标准 var clientCred = new ClientCredential(AppClientId, AppClientSecret); result = await _context.AcquireTokenAsync(Dyna
var clientCred = new ClientCredential(AppClientId, AppClientSecret);
result = await _context.AcquireTokenAsync(DynamicsTenantUrl, clientCred);
Token = result.AccessToken;
但是,我为其构建此连接的应用程序有一个长期运行的操作,该操作最终从Dynamics获得“未授权”,因为令牌已过期
我已经看了几个例子,其中我需要获取refresh_令牌,然后请求该信息以保持连接,但是上面没有给我一个refresh令牌
我尝试过使用这个方法,尽管它在令牌缓存中显示了一个令牌,但它总是返回“No token available”
有没有办法在当前的实现中做到这一点,或者我需要完全更改连接代码才能访问此令牌?我无法想象如何在他们的Active Directory软件包中做到这一点。然而,对于oauth来说,这个包似乎是一个相当薄的包装。我不知道他们为什么要推广一个定制库来做一些像Oauth 2.0原型一样被广泛支持和通用的事情 通过在oauth请求的作用域中包含
offline\u access
,我得到了一个刷新令牌,然后可以使用它来获取您所需的任意多个访问令牌。没有很好的文档
获取刷新令牌
注意:您可能希望使用带有web服务器流的通用oauth 2库来完成此任务
GEThttps://login.microsoftonline.com//oauth2/authorize?client_id=&response_type=code&redirect_uri=&response_mode=query&scope=offline_access&resource=
(注意:您将需要其他作用域,具体取决于您对令牌所做的操作,即,对我而言,它是offline\u访问https://admin.services.crm.dynamics.com/user_impersonation https://graph.microsoft.com/User.Read
POST https://login.microsoftonline.com/<tenant_id>/oauth2/token
client_id: <client_id>
scope: <scope>
grant_type: refresh_token
client_secret: <client_secret>
resource: <tenant_url>
POSThttps://login.microsoftonline.com//oauth2/token
客户识别码:
范围:
授权类型:刷新令牌
客户机密:
资源:
注意:这些将是经过url编码的表单(通常由oauth库为您处理)
大图您可以使用web服务器的任何标准oauth文档和刷新令牌流来指导您。ms dynamics特定的内容是范围值,需要在您的请求中包含资源(oauth的一部分,只是在我的经验中没有太多使用)我不知道如何使用他们的Active Directory软件包实现这一点。不过,似乎该软件包对oauth来说是一个相当薄的包装。我不确定他们为什么要推广一个自定义库来完成一些像oauth 2.0 protocoal一样广受支持和通用的功能 通过在oauth请求的作用域中包含
offline\u access
,我得到了一个刷新令牌,然后可以使用它来获取您所需的任意多个访问令牌。没有很好的文档
获取刷新令牌
注意:您可能希望使用带有web服务器流的通用oauth 2库来完成此任务
GEThttps://login.microsoftonline.com//oauth2/authorize?client_id=&response_type=code&redirect_uri=&response_mode=query&scope=offline_access&resource=
(注意:您将需要其他作用域,具体取决于您对令牌所做的操作,即,对我而言,它是offline\u访问https://admin.services.crm.dynamics.com/user_impersonation https://graph.microsoft.com/User.Read
POST https://login.microsoftonline.com/<tenant_id>/oauth2/token
client_id: <client_id>
scope: <scope>
grant_type: refresh_token
client_secret: <client_secret>
resource: <tenant_url>
POSThttps://login.microsoftonline.com//oauth2/token
客户识别码:
范围:
授权类型:刷新令牌
客户机密:
资源:
注意:这些将是经过url编码的表单(通常由oauth库为您处理)
大图您可以使用web服务器的任何标准oauth文档和刷新令牌流来指导您。ms dynamics特定的内容是范围值,需要在您的请求中包含资源(oauth的一部分,只是在我的经验中没有太多使用)这是C#webapi核心示例,使用ADAL库,如果在ADAL缓存中过期,则获取。
替换D365 url、clientid、客户端密码和基地址
namespace Microsoft.Crm.Sdk.Samples{
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading.Tasks;
public class Authentication
{
private HttpMessageHandler _clientHandler = null;
private AuthenticationContext _context = null;
private string _authority = null;
private string _resource = "https://xxxxx.api.crm.dynamics.com/";
private string _clientId = "ddfsdfadsfdfadssddf";
private string _clientSecret = "dsdfgfdgdfgfdgfd";
public Authentication() { SetClientHandler(); }
public AuthenticationContext Context
{
get
{ return _context; }
set
{ _context = value; }
}
public HttpMessageHandler ClientHandler
{
get
{ return _clientHandler; }
set
{ _clientHandler = value; }
}
public string Authority
{
get
{
if (_authority == null)
_authority = DiscoverAuthority(_resource);
return _authority;
}
set { _authority = value; }
}
public AuthenticationResult AcquireToken()
{
try
{
var clientA = new ClientCredential(_clientId, _clientSecret);
return Context.AcquireTokenAsync(_resource, clientA).Result;
}
catch (Exception e)
{
throw new Exception("Authentication failed. Verify the configuration values are correct.", e); ;
}
}
public static string DiscoverAuthority(string serviceUrl)
{
try
{
AuthenticationParameters ap = AuthenticationParameters.CreateFromUrlAsync(
new Uri(serviceUrl + "api/data/")).Result;
var strOAuth = ap.Authority.Substring(0, ap.Authority.LastIndexOf("/"));
return strOAuth.Substring(0, strOAuth.LastIndexOf("/"));
}
catch (HttpRequestException e)
{
throw new Exception("An HTTP request exception occurred during authority discovery.", e);
}
catch (System.Exception e)
{
// This exception ocurrs when the service is not configured for OAuth.
if (e.HResult == -2146233088)
{
return String.Empty;
}
else
{
throw e;
}
}
}
private void SetClientHandler()
{
_clientHandler = new OAuthMessageHandler(this, new HttpClientHandler());
_context = new AuthenticationContext(Authority, true);
}
class OAuthMessageHandler : DelegatingHandler
{
Authentication _auth = null;
public OAuthMessageHandler(Authentication auth, HttpMessageHandler innerHandler)
: base(innerHandler)
{
_auth = auth;
}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
// It is a best practice to refresh the access token before every message request is sent. Doing so
// avoids having to check the expiration date/time of the token. This operation is quick.
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _auth.AcquireToken().AccessToken);
return base.SendAsync(request, cancellationToken);
}
}
}
public class LongRunningOperation
{
private HttpClient httpClient;
private void ConnectToCRM(String[] cmdargs)
{
Authentication auth = new Authentication();
httpClient = new HttpClient(auth.ClientHandler, true);
httpClient.BaseAddress = new Uri("https://xxxxxx.api.crm.dynamics.com/" + "api/data/v9.1/");
httpClient.Timeout = new TimeSpan(0, 2, 0);
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
private async System.Threading.Tasks.Task<Guid> CreateImportMap()
{
var importMap = new JObject();
Console.WriteLine("--Section 1 started--");
importMap.Add("name", "Import Map " + DateTime.Now.Ticks.ToString());
importMap.Add("source", "Import Accounts.csv");
importMap.Add("description", "Description of data being imported");
importMap.Add("entitiesperfile", 1);
HttpRequestMessage requestWebAPI =
new HttpRequestMessage(HttpMethod.Post, "importmaps");
requestWebAPI.Content = new StringContent(importMap.ToString(),
Encoding.UTF8, "application/json");
requestWebAPI.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
HttpResponseMessage responseWebAPI =
await httpClient.SendAsync(requestWebAPI);
if (responseWebAPI.StatusCode == HttpStatusCode.NoContent) //204
{
Console.WriteLine("Import Map '{0} {1}' created.",
importMap.GetValue("name"), importMap.GetValue("source"));
string mapUri = responseWebAPI.Headers.
GetValues("OData-EntityId").FirstOrDefault();
string EntityId = mapUri.Substring(mapUri.IndexOf('(') + 1, 36);
Console.WriteLine("Map URI: {0}", mapUri);
return new Guid(EntityId);
}
else
{
Console.WriteLine("Failed to create ImportMap1 for reason: {0}",
responseWebAPI.ReasonPhrase);
throw new Exception(responseWebAPI.Content.ToString());
}
}
public async void Run()
{
while (true)
{
Guid importMapId = await CreateImportMap();
Thread.Sleep(10000);
}
}
#region Main method
static public void Main(string[] args)
{
try
{
var app = new LongRunningOperation();
app.ConnectToCRM(args);
app.Run();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("Press <Enter> to exit.");
Console.ReadLine();
}
}
#endregion Main method
}}
namespace Microsoft.Crm.Sdk.Samples{
使用Newtonsoft.Json.Linq;
使用制度;
使用System.Linq;
Net系统;
使用System.Net.Http;
使用System.Net.Http.Header;
使用系统文本;
使用系统线程;
使用Microsoft.IdentityModel.Clients.ActiveDirectory;
使用System.Threading.Tasks;
公共类身份验证
{
私有HttpMessageHandler _clientHandler=null;
私有身份验证上下文_context=null;
私有字符串_authority=null;
私有字符串_资源=”https://xxxxx.api.crm.dynamics.com/";
私有字符串_clientId=“ddfsdfadsfdffadsddf”;
私有字符串_clientSecret=“dsdfgfdgdgffd”;
公共身份验证(){SetClientHandler();}
公共身份验证上下文
{
得到
{return_context;}
设置
{{u context=value;}
}
公共HttpMessageHandler客户端处理程序
{
得到
{return\u clientHandler;}
设置
{u clientHandler=value;}
}
公共字符串管理局
{
得到
{
如果(_authority==null)
_权限=发现权限(_资源);
返回(u)权限;;
}
设置{u authority=value;}
}
公共身份验证结果AcquireToken()
{
尝试
{
var clientA=新的ClientCreden