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 ...
随机推荐
- CAD绘图效率低?教你4个CAD绘图技巧,绘图效率提升十倍
CAD绘图一直是一个谜一样的存在,说它简单吧,很多人都无法完全精通,说它难吧,很多人也都自学成才了. 如何学好CAD绘图是个难题,但是老话说的好,只要思想不滑坡,办法总比困难多,掌握以下这些CAD绘图 ...
- laravel 框架源码分析
laravel框架的文档中的例子很多时候不是很明显,所以想要真正的使用好这个框架,我们可以尝试去阅读它源码中的注释(不得不说laravel源码的注释还是很详细的). 我们先来看一下laravel 的文 ...
- Vue---记一次通过{{}}获取json数据-页面渲染不出来的坑
前两天干活儿的时候碰到一个Vue的问题,让我这个菜鸡完全摸不到头脑,需求如下:前端页面点击表格中的某一行的详情按钮,会弹出一个Dialog,然后Dialog中有选项卡,选项卡中再有具体的table来展 ...
- net.sf.json将string转为map
背景 改一个以前的项目,项目里只有这个包,虽然我想用gson或者fastjson,然而并不想引入新的jar.于是使用这个,特此记录,感觉贼不好用. 实现代码 entity.getData()的值:{a ...
- Redis 数据淘汰机制
为了更好的利用内存,使Redis存储的都是缓存的热点数据,Redis设计了相应的内存淘汰机制(也叫做缓存淘汰机制) 通过maxmemory 配置项来设置允许用户使用的最大内存大小,当内存数据集大小达到 ...
- spark shell操作
RDD有两种类型的操作 ,分别是Transformation(返回一个新的RDD)和Action(返回values). 1.Transformation:根据已有RDD创建新的RDD数据集build ...
- Java_可变参数类型
Java方法中的可变参数类型,也称为不定参数类型,是一个非常重要的概念 举栗子 public class TestVarArgus { public static void dealArray(int ...
- java中使用lambda表达式
使用lambda表达式能够使复杂的编写方式变的简单 lambda表达式的语法 (parameters) -> expression 或 (parameters) ->{ statement ...
- IDEA中写MyBatis的xml配置文件编译报错的坑
IDEA中写MyBatis的xml配置文件编译报错的坑 说明:用IDEA编译工具在项目中使用Mybatis框架,编写mybatis-config.xml和Mapper.xml配置文件时,编译项目出现错 ...
- [CodeForces - 1272D] Remove One Element 【线性dp】
[CodeForces - 1272D] Remove One Element [线性dp] 标签:题解 codeforces题解 dp 线性dp 题目描述 Time limit 2000 ms Me ...