Dynamics crm Dynamics Web API-刷新令牌

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

我正在使用Dynamics Web API和Microsoft.IdentifyModel.Clients.ActiveDirectory包从Azure函数(.NET Core)应用程序连接到Dynamics

我的连接相当标准

        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