【转】!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的话,如下图:

下面就是用代码如何做了,不多说,看代码:

 
  1. using Newtonsoft.Json;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net.Http;
  5. using System.Net.Http.Headers;
  6. using System.Threading.Tasks;
  7.  
  8. namespace UsingWebAPI
  9. {
  10. public class AuthenticationResponse
  11. {
  12. public string access_token { get; set; }
  13. public int expires_in { get; set; }
  14. public int expires_on { get; set; }
  15. public int ext_expires_in { get; set; }
  16. public int not_before { get; set; }
  17. public string resource { get; set; }
  18. public string token_type { get; set; }
  19. }
  20. class Program
  21. {
  22.  
  23. static string resourceUrl = "https://crm219270.crm5.dynamics.com/";
  24. static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29";
  25. static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ";
  26. static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d";
    static void Main(string[] args)
  27. {
  28. GetAuthenticationResponse();
  29. Console.ReadKey();
  30. }
  31.  
  32. private static async void GetAuthenticationResponse()
  33. {
  34. List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>();
  35.  
  36. vals.Add(new KeyValuePair<string, string>("client_id", clientId));
  37. vals.Add(new KeyValuePair<string, string>("resource", resourceUrl));
  38. vals.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
  39. vals.Add(new KeyValuePair<string, string>("client_secret", clientSecret));
  40. string tokenUrl = string.Format("https://login.windows.net/{0}/oauth2/token", tenantId);
  41.  
  42. using (HttpClient httpClient = new HttpClient())
  43. {
  44. httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
  45. HttpContent content = new FormUrlEncodedContent(vals);
  46. HttpResponseMessage hrm = httpClient.PostAsync(tokenUrl, content).Result;
  47. AuthenticationResponse authenticationResponse = null;
  48. if (hrm.IsSuccessStatusCode)
  49. {
  50. string data = await hrm.Content.ReadAsStringAsync();
  51. authenticationResponse = JsonConvert.DeserializeObject<AuthenticationResponse>(data);
  52. await DataOperations(authenticationResponse);
  53. }
  54. else
  55. {
  56. Console.WriteLine("Error." + hrm.ReasonPhrase);
  57. }
  58. }
  59. }
  60.  
  61. private static async Task DataOperations(AuthenticationResponse authResult)
  62. {
  63. using (HttpClient httpClient = new HttpClient())
  64. {
  65. httpClient.BaseAddress = new Uri(resourceUrl);
  66. httpClient.Timeout = new TimeSpan(, , ); //2 minutes
  67. httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
  68. httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
  69. httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  70. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.access_token);
  71. string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = ""});
  72. HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts");
  73. request.Content = new StringContent(content);
  74. request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
  75. HttpResponseMessage response = await httpClient.SendAsync(request);
  76. if (response.IsSuccessStatusCode)
  77. {
  78. Console.WriteLine("Account created.");
  79. }
  80. else
  81. {
  82. Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase));
  83. }
  84. }
  85. }
  86. }
  87. }

当然,如果使用ADAL的话,代码会更加简单点:

 
  1. using Microsoft.IdentityModel.Clients.ActiveDirectory;
  2. using Newtonsoft.Json;
  3. using System;
  4. using System.Net.Http;
  5. using System.Net.Http.Headers;
  6.  
  7. namespace UsingWebAPI
  8. {
  9. class Program
  10. {
  11.  
  12. static string resourceUrl = "https://crm219270.crm5.dynamics.com/";
  13. static string clientId = "de8dd947-a3e3-48ec-8602-c3063f11dc29";
  14. static string clientSecret = "5FsXh2*oNyLRm]Go1a9hD.[]=k54GNOZ";
  15. static string tenantId = "3e28b187-1c5c-42f5-a1be-3f47570da35d";
  16.  
  17. static void Main(string[] args)
  18. {
  19. AuthAndInvoke();
  20. Console.ReadKey();
  21. }
  22.  
  23. private static async void AuthAndInvoke()
  24. {
  25. var credentials = new ClientCredential(clientId, clientSecret);
  26. var authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId);
  27. var result = await authContext.AcquireTokenAsync(resourceUrl, credentials);
  28. using (HttpClient httpClient = new HttpClient())
  29. {
  30. httpClient.BaseAddress = new Uri(resourceUrl);
  31. httpClient.Timeout = new TimeSpan(, , ); //2 minutes
  32. httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
  33. httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
  34. httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  35. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
  36. string content = JsonConvert.SerializeObject(new { name = "A Account", telephone1 = "" });
  37. HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "api/data/v9.1/accounts");
  38. request.Content = new StringContent(content);
  39. request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
  40. HttpResponseMessage response = await httpClient.SendAsync(request);
  41. if (response.IsSuccessStatusCode)
  42. {
  43. Console.WriteLine("Account created.");
  44. }
  45. else
  46. {
  47. Console.WriteLine(String.Format("Failed to create account, reason is '{0}'.", response.ReasonPhrase));
  48. }
  49. }
  50. }
  51. }
  52. }

可以看到代码创建的account的owner是我们前面步骤的Application User,是以该用户身份在运行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JMM(java内存模型)

这篇文章写得挺好的&#xff1a;https://blog.csdn.net/javazejian/article/details/72772461 在多线程环境下&#xff0c;线程之间的要通信,就不得不提JMM(java内存模型) 在JVM内部使用的java内存模型(JMM)将线程堆栈和堆之间的内存分开 jmm的承诺&#xff1a; 1.原子性 2.可…

【转】Postman 生成接口文档

引言 几个朋友想做一个前后端分离的项目&#xff0c;接口文档的重要性那是不言而喻的。生成接口文档的方法真的太多了&#xff0c;Yapi、Swagger等等。但是想公网上访问接口文档并修改的话&#xff0c;还得购买服务器&#xff0c;部署上去。穷码农&#xff0c;哪有钱购买服务器…

JVM的进阶学习(GC Roots、JVM调优与参数配置、)

1. GC Roots&#xff0c;可达性分析 从GC roots的对象作为起始点&#xff0c;从GC Roots对象开始向下搜索&#xff0c;如果一个对象到GCRoots没有任何引用链相连&#xff0c;则说明对象不可用。即给定一个集合的引用作为根出发&#xff0c;通过引用关系遍历对象图&#xff0c;能…

【转】图解phpstorm常用快捷键

转载自 https://segmentfault.com/a/1190000004225643 查询快捷键 CTRLN 查找类 CTRLSHIFTN 全局搜索文件 ,优先文件名匹配的文件 CTRLSHIFTALTN 查找php类名/变量名 ,js方法名/变量名, css 选择器 CIRLB 找变量的来源&#xff0c;跳到变量申明处 (CTRL 鼠标单击 也可以) CTRL…

HQL写topN、Spark写topN

HQL写topN用窗口函数rank() 、row_number()、dense_rank() 1、rank(),跳跃排序&#xff0c;假如第一第二相同&#xff0c;那么第三个就是3 select * from( select id, cn, score, rank() over(partition by id order by score desc)as ranks from top N ) A where ranks&…

【转】Dynamics 365 CRM 开发架构简介

目录 概览 名词解释连接到Dynamics 365 CRM Web APIOrganization service选择 - Web API vs. Organization service扩展服务端扩展应用端正文 Dynamics 365 CRM提供了多种编程模型&#xff0c;你可以灵活地按需选用最佳模式。 本文是对Dynamics 365 CRM编程模型的综述。 回…

查找算法-(顺序查找、二分查找、插值查找、斐波那契查找)

1&#xff09;顺序查找或叫线性查找 就是顺序遍历匹配 2&#xff09;二分查找 package search;public class BinarySearch {/*** 二分查找数组必须有序*//**** param arr 数组* param left 左边索引* param right 右边索引* param findVal 要查找的值* return 找到就返回&…

数据结构 - 哈希表(用数组+链表实现存储员工信息,添加增删查功能)

package hashtab;import java.util.Scanner;public class HashTabDemo {public static void main(String[] args) {//创建一个hashTabHashTab hashTab new HashTab(7);//写一个简单菜单来测试String key "";Scanner sc new Scanner(System.in);while (true){Syste…

数据结构 - 树(二叉树的 前序、中序、后序 遍历)

二叉树遍历&#xff08;前序中序后序&#xff0c;主要是看父节点的输出顺序&#xff09; package tree;public class BinaryTreeDemo {public static void main(String[] args) {//先需要创建一颗二叉树BinaryTree binaryTree new BinaryTree();//创建需要的节点HeroNode root…

【转】c# 操作webservice(经典入门教程+MSDN必胜)(有自己修改的部分)

Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求&#xff0c;轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件&#xff08;服务&#xff09;&#xff0c;使用WSDL文件进行&#xff0…

数据结构 - 二叉树(前序中序后序查找)

public static int i 1, j 1, k 1;//编写前序查找方法public HeroNode preOrderSearch(int no){System.out.println("前序遍历"(i)"次");if (this.no no){return this;}HeroNode heroNode null;if (this.left ! null){heroNode this.left.preOrderSea…

数据结构 - 二叉树(删除节点)

因为二叉树是单向的&#xff0c;所以要判断当前节点的子节点(左或右)是否是被删除的节点 //递归删除节点//规定&#xff1a;如果是叶子节点就删除节点&#xff0c;如果非叶子节点就删除子树public void delNode(int no){if (this.left !null && this.left.no no){this…

【转】OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service Client

一、概念介绍 1.1&#xff0c;什么是OData&#xff1f; 还是看OData官网的简单说明&#xff1a; An open protocol to allow the creation and consumption of queryable and interoperable RESTful APIs in a simple and standard way. 这是一个开放的数据查询和服务协议&…

数据结构 - 顺序存储二叉树(前序中序后序遍历)

就是逻辑上是二叉树&#xff0c;物理上是一个数组 需求 package tree;public class ArrayBinaryTreeDemo {public static void main(String[] args) {int arr [] {1, 2, 3, 4, 5, 6, 7};ArrayBinaryTree arrayBinaryTree new ArrayBinaryTree(arr);//arrayBinaryTree.preOrde…

【转】WCF Data Service 使用小结 (一)—— 了解OData协议

最近做了一个小项目&#xff0c;其中用到了 WCF Data Service&#xff0c;之前是叫 ADO.NET Data Service 的。关于WCF Data Service&#xff0c;博客园里的介绍并不多&#xff0c;但它确实是个很好的框架。可以很方便地通HTTP来访问数据库&#xff0c;如果你是做富客户端开发的…

数据结构 - 线索化二叉树(线索化与遍历)

!!(这里我debug很久才理解过来)** 这里8的前驱为null&#xff0c;所以8的leftType1&#xff0c;但是6是没有后继的或者说后继为null但是rightType为0(因为后继是在下一个节点来进行连接的&#xff0c;6没有下一个节点&#xff0c;所以不能实现后继的线索化&#xff0c;所以righ…

【转】WCF Data Service 使用小结(二) —— 使用WCF Data Service 创建OData服务

在 上一章 中&#xff0c;介绍了如何通过 OData 协议来访问 OData 服务提供的资源。下面来介绍如何创建一个 OData 服务。在这篇文章中&#xff0c;主要说明在.NET的环境下&#xff0c;如何使用 WCF Data Service 来创建OData服务。当然&#xff0c;对于 JAVA 或者其它平台&…

算法 - 堆排序(大顶堆、小顶堆)

用的是顺序存储二叉树&#xff0c;也就是数组实现的二叉树&#xff0c;遍历的时候按照的是二叉树的形式 代码实现 package tree;import java.util.Arrays;public class HeapSort {public static void main(String []args){int [] arr {4, 6, 8, 5, 9,-1,-1,2,4,5,6,88};heapS…

【转】WCF Odata 开放数据协议应用

OData简介 说起 WCF Data Service &#xff0c;不得不说的是 OData。对于一个标准的 Web 服务&#xff0c;它往往会提供了一些功能&#xff0c;比如说&#xff1a;订货、退货这些&#xff0c;然后使用者通过HTTP协议来使用这些功能。这是面向服务的基本思想&#xff0c;然而面…

数据结构 - 赫夫曼树

wpl最小的就是赫夫曼树(所有叶子节点的带权路径长度之和最小) 写出来两个节点连接&#xff0c;然后循环就可以了 package tree.huffmantree;import java.util.ArrayList; import java.util.Collections; import java.util.List;public class huffmanTree {public static void …