Dynamics 365 Online通过OAuth 2 Client Credential授权(Server-to-Server Authentication)后调用Web API
微软动态CRM专家罗勇 ,回复332或者20190505可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!
本文很多内容来自 John Towgood 撰写的Dynamics 365 Online Authenticate with Client Credentials ,也着重参考了官方的 Use Single-Tenant server-to-server authentication ,我根据新的Azure Portal界面做了一些操作上的变化,并且改了一些代码,还使用ADAL来简化代码。
登录 https://portal.azure.com ,点击左边的 【Azure Active Directory】 ,然后再点击 【App registrations】 ,再点击【New registration】

输入一个合适的名称,Supported account types保持默认的 Accounts in this organizational directory only (Orgname) 不变,点击【Register】按钮。因为Redirect URI用不上所以不输入。

注册成功后会产生 Application (client) ID,记录下来备用,同时也记录下 Directory (tenant) ID。

再点击左边的【API Permissions】,再点击右边的 【+ Add a permission】按钮。

选择 【Dynamics CRM】 (也可以选择使用 PowerApps Runtime Serive 这个权限),

选择 【Delegated permissions】 > 【user_impersonation】后点击【Add permissions】按钮。

然后点击【Grant admin consent for Orgname】,

在弹出的提示中选择【Yes】。

然后点击【Certificates & secrets】 > 【+ New client secret】,输入合适的Description,在点击【Add】按钮。

会自动生成Client secrets,这里需要点击生成的secret旁边的【copy to clipboard】图标将其复制下来,记得在这个步骤复制下来,因为离开这个页面后就看不到这个secret了。

然后需要创建 一个Azure AD 用户,点击左侧的【Azure Active Directory】> 【Users】。

然后点击【New user】。

为用户输入Name,User Name,然后点击【Create】按钮。

最后还需要到Dynamics 365 Customer Engagement中创建一个Application User。导航到 Settings > Security > Users,切换到【Application Users】,点击命令栏的【NEW】按钮。

记得要切换到 APPLICATION USER这个窗体,输入的内容如下,Application ID就是前面步骤记录的Application (client) ID,其余的就是前面步骤创建的Azure AD user信息。

保存后会自动填充 Application ID URI 和 Azure AD Object ID 字段的值。

当然还需要给这个用户授予至少一个角色才行,官方建议不要授予系统标准角色,我这里复制了一个标准角色授予给他。
如果用Postman来获取access token的话,如下图:

下面就是用代码如何做了,不多说,看代码:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks; namespace UsingWebAPI
{
public class AuthenticationResponse
{
public string access_token { get; set; }
public int expires_in { get; set; }
public int expires_on { get; set; }
public int ext_expires_in { get; set; }
public int not_before { get; set; }
public string resource { get; set; }
public string token_type { get; set; }
}
class Program
{ static string resourceUrl = "https://crm219270.crm5.dynamics.com/";
static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29";
static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ";
static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d";
static void Main(string[] args)
{
GetAuthenticationResponse();
Console.ReadKey();
} private static async void GetAuthenticationResponse()
{
List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>(); vals.Add(new KeyValuePair<string, string>("client_id", clientId));
vals.Add(new KeyValuePair<string, string>("resource", resourceUrl));
vals.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
vals.Add(new KeyValuePair<string, string>("client_secret", clientSecret));
string tokenUrl = string.Format("https://login.windows.net/{0}/oauth2/token", tenantId); using (HttpClient httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
HttpContent content = new FormUrlEncodedContent(vals);
HttpResponseMessage hrm = httpClient.PostAsync(tokenUrl, content).Result;
AuthenticationResponse authenticationResponse = null;
if (hrm.IsSuccessStatusCode)
{
string data = await hrm.Content.ReadAsStringAsync();
authenticationResponse = JsonConvert.DeserializeObject<AuthenticationResponse>(data);
await DataOperations(authenticationResponse);
}
else
{
Console.WriteLine("Error." + hrm.ReasonPhrase);
}
}
} private static async Task DataOperations(AuthenticationResponse authResult)
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(resourceUrl);
httpClient.Timeout = new TimeSpan(, , ); //2 minutes
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.access_token);
string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = ""});
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts");
request.Content = new StringContent(content);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
HttpResponseMessage response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Account created.");
}
else
{
Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase));
}
}
}
}
}
当然,如果使用ADAL的话,代码会更加简单点:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers; namespace UsingWebAPI
{
class Program
{ static string resourceUrl = "https://crm219270.crm5.dynamics.com/";
static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29";
static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ";
static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d"; static void Main(string[] args)
{
AuthAndInvoke();
Console.ReadKey();
} private static async void AuthAndInvoke()
{
var credentials = new ClientCredential(clientId, clientSecret);
var authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId);
var result = await authContext.AcquireTokenAsync(resourceUrl, credentials);
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(resourceUrl);
httpClient.Timeout = new TimeSpan(, , ); //2 minutes
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = "" });
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts");
request.Content = new StringContent(content);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
HttpResponseMessage response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Account created.");
}
else
{
Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase));
}
}
}
}
}
可以看到代码创建的account的owner是我们前面步骤的Application User,是以该用户身份在运行的。

Dynamics 365 Online通过OAuth 2 Client Credential授权(Server-to-Server Authentication)后调用Web API的更多相关文章
- 利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API
微软动态CRM专家罗勇 ,回复337或者20190521可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 配置Dynamics 365 & PowerApps 支 ...
- Dynamics 365 CE的插件/自定义工作流活动中调用Web API示例代码
微软动态CRM专家罗勇 ,回复325或者20190428可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 现在Web API越来越流行,有时候为了程序更加健壮,需要在插件 ...
- Dynamics 365本地部署版本配置OAuth 2 Password Grant以调用Web API
微软动态CRM专家罗勇 ,回复330或者20190504可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 根据官方建议,不要再使用Dynamics 365 Custome ...
- Dynamics CRM中跨域调用Web API 2
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复224或者20160611可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...
- 用Web API Client 调用 Web API
安装Web API客户端库 右键单击项目,选择管理 NuGet程序包,选择联机选项,选择全部,在搜索框中输入“Microsoft.AspNet.WebApi.Client”, 搜索结果就是要安装的类库 ...
- 解决Dynamics 365使用JS调用Web API时报no property value was found in the payload 错误。
摘要: 微软动态CRM专家罗勇 ,回复323或者20190421可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 碰到如下报错: message: "An er ...
- 配置Postman通过OAuth 2 implicit grant获取Dynamics 365 CE Online实例的Access Token
微软动态CRM专家罗勇 ,回复335或者20190516可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 对于测试Web API, Get 类型,不需要设定特别reque ...
- Dynamics CRM模拟OAuth请求获得Token后在外部调用Web API
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复233或者20161104可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...
- Dynamics 365 App for Outlook 与 Dynamics 365 for Outlook(已被弃用)
在最新的版本中Dynamics 365 for Outlook(Outlook 客户端)已被弃用 随 Dynamics CRM 2016(版本 8.0)引入的 Dynamics 365 App for ...
随机推荐
- 学生选课系统v1.0
最近两天写了下老师课上留的作业:学生选课系统.感觉自己写的特别麻烦,思路特别不清晰,平常自己总会偷懒,一些太麻烦细节的功能就不去实现了,用简单的功能来替代,直到自己这回写完这个系统(但自己写的比较lo ...
- MPV源码探究:背景及准备工作
背景及准备工作 一点历史 古有魏蜀吴三分天下,今有 Mplayer.MPC.VLC 三分天下.这个世界观太庞大,忍不住先讲一点多媒体播放器的历史.实际上目前市面上的开源播放器主要基于三种技术栈: Mp ...
- 设置POP3/SMTP协议 手机绑定邮箱
例如设置企业邮箱 一.设置POP3/SMTP协议,意思是代收邮件致本地POP3接收邮件服务器:pop.qiye.qq.comSMTP发送邮件服务器:smtp.qiye.qq.com二.设置IMAP/S ...
- C++ std::deque 基本用法
#include <iostream> #include <string> #include <deque> // https://zh.cppreference. ...
- Python 中国象棋源码 V1
Pygame 做的中国象棋,一直以来喜欢下象棋,写了 python 就拿来做一个试试,水平有限,电脑走法水平低,需要在下次版本中更新电脑走法,希望源码能帮助大家更好的学习 python.总共分为四个文 ...
- 原创 Hive count 多个度量指标,带有 distinct
Hive count 多个度量指标,带有 distinct ,注意点!!! 比如 select organid, ppi, count(id1) as num1, count(distinct ...
- WPF使用FlowDocument实现图文混排
代码: <RichTextBox CaretBrush="#fff" Background="Transparent" BorderThickness=& ...
- 3.java基础之关键字instanceof
1. instanceof 使用:对象引用名 instanceof 类名 作用:来判读引用的对象和类名是否兼容(是否继承该类,或爷爷辈的类) 例子: Team team = new Team(); t ...
- Java并发J.U.C学习总结
转载自http://www.cnblogs.com/chenpi/结合自己理解稍有添加自己的理解 阅读目录 JSR 166及J.U.C Executor框架(线程池. Callable .Future ...
- C# net core程序调试错误集(持续更新)
目录 C#程序调试错误集 1.依赖注入错误System.InvalidOperationException: Unable to resolve service for type 'xxx' whil ...