微软动态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的更多相关文章

  1. 利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API

    微软动态CRM专家罗勇 ,回复337或者20190521可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 配置Dynamics 365 & PowerApps 支 ...

  2. Dynamics 365 CE的插件/自定义工作流活动中调用Web API示例代码

    微软动态CRM专家罗勇 ,回复325或者20190428可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 现在Web API越来越流行,有时候为了程序更加健壮,需要在插件 ...

  3. Dynamics 365本地部署版本配置OAuth 2 Password Grant以调用Web API

    微软动态CRM专家罗勇 ,回复330或者20190504可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 根据官方建议,不要再使用Dynamics 365 Custome ...

  4. Dynamics CRM中跨域调用Web API 2

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复224或者20160611可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  5. 用Web API Client 调用 Web API

    安装Web API客户端库 右键单击项目,选择管理 NuGet程序包,选择联机选项,选择全部,在搜索框中输入“Microsoft.AspNet.WebApi.Client”, 搜索结果就是要安装的类库 ...

  6. 解决Dynamics 365使用JS调用Web API时报no property value was found in the payload 错误。

    摘要: 微软动态CRM专家罗勇 ,回复323或者20190421可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 碰到如下报错: message: "An er ...

  7. 配置Postman通过OAuth 2 implicit grant获取Dynamics 365 CE Online实例的Access Token

    微软动态CRM专家罗勇 ,回复335或者20190516可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 对于测试Web API, Get 类型,不需要设定特别reque ...

  8. Dynamics CRM模拟OAuth请求获得Token后在外部调用Web API

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复233或者20161104可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  9. Dynamics 365 App for Outlook 与 Dynamics 365 for Outlook(已被弃用)

    在最新的版本中Dynamics 365 for Outlook(Outlook 客户端)已被弃用 随 Dynamics CRM 2016(版本 8.0)引入的 Dynamics 365 App for ...

随机推荐

  1. ASP.NET操作Excel

    使用NPOI操作Excel,无需Office COM组件 部分代码来自于:https://docs.microsoft.com/zh-tw/previous-versions/ee818993(v=m ...

  2. 【转】CAP 定理的含义

    原文链接:CAP 定理的含义 作者: 阮一峰 日期: 2018年7月16日 分布式系统(distributed system)正变得越来越重要,大型网站几乎都是分布式的. 分布式系统的最大难点,就是各 ...

  3. REST架构指导方案

    目录 REST架构指导方案 何为REST 在WEB系统中应用REST风格 应用约束 对资源应用正确的动词语义 名词性的URI地址 RESTFUL的URL路径实践 单一资源的路径制定 复杂查询的路径制定 ...

  4. Spring Cloud进阶之路 | 一:服务注册与发现(nacos)

    转载请注明作者及出处: 作者:银河架构师 原文链接:https://www.cnblogs.com/luas/p/12068846.html 1.版本 最新稳定版本为1.1.4,也可以从发版说明.博客 ...

  5. 安装指定版本的tensorflow(我报错了)

    安装命令如下: pip install tensorflow-gpu==1.10.0 -i https://pypi.tuna.tsinghua.edu.cn/simple 慎用,反正我报错了,而且还 ...

  6. 前端面试题套路--终极版(Vue、JavaScript)

    前言 面试题是永远都准备不完的!!!!! 前端常见的一些问题 1.前端性能优化手段? 1. 尽可能使用雪碧图 2. 使用字体图标代替图片 3. 对HTML,css,js 文件进行压缩 4. 模块按需加 ...

  7. NestedScrollView、ScrollView 加载完自动滑动至底部问题的解决方案

    正常情况下,由于NestedScrollView/ScrollView 嵌套RecyclerView,可能会导致Recyclerview占据焦点导致整个NestedScrollView/ScrollV ...

  8. Spring Boot修改JSP不用重启的办法

    在application.properties文件中添加一行代码解决. Spring Boot 2.0以上添加如下一行: server.servlet.jsp.init-parameters.deve ...

  9. ssdb make 失败 autoconf required

    ERROR! autoconf required! install autoconf first Makefile:4: build_config.mk: No such file or direct ...

  10. nginx 校验及重启

    #查询nginx所在路径 [centos find 查询文件](https://www.cnblogs.com/codeWorldCodeHeart/p/12049262.html) #校验如下 /u ...