Dynamics 365 Online通过OAuth 2 Client Credential授权(Server-to-Server Authentication)后调用Web API

news/2025/2/21 4:51:42/文章来源:https://www.cnblogs.com/parkerchen/p/18719591

本文很多内容来自 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(0, 2, 0); //2 minuteshttpClient.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 = "123456789"});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(0, 2, 0); //2 minuteshttpClient.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 = "123456789" });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,是以该用户身份在运行的。

 

 

 

原文地址:https://www.cnblogs.com/luoyong0201/p/dynamics_365_oauth2_client_credentials_server_to_server_authentication_web_api.html

 

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

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

相关文章

【转载】在Visual Studio 2015中添加报表功能 (使用 VS2015打开c#项目,新建文件没有报表选项,或者打开已有的wsdl不能打开设计器 )

Visual Studio 2015默认安装时没有报表,这时需要添加Microsoft Office 开发人员工具、Microsoft SQL Server Data Tools选项,安装之后就可以显示报表了,具体操作如下。方法/步骤 双击Visual Studio 2015的安装程序图标,启动软件安装向导。 在Visual Studio软件安装向导对话…

BUUCTF-PWN-jarvisoj_level2

这道题对我来说有点新奇,它利用了程序中自带的system程序,和字符/bin/bash构造了一个后门函数让我们看看是怎么做的吧 首先和程序进行交互:发现是一个读取输入相关的程序,我们对其进行分析,首先用checksec检测到了NX保护,但是没关系。我们再用IDA进行程序的分析:我们看到…

推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!

在AI技术飞速发展的今天,大语言模型(LLM)的应用越来越广泛,但高昂的使用成本常常让个人开发者和小型团队望而却步。今天,我要为大家介绍一个非常实用的开源项目——DeepSeek-Free-API,它能够让你免费接入DeepSeek大模型,轻松实现各种AI功能。 1、项目简介 DeepSeek-Free…

Deepseek+Cherry Studio,打造便利的AI大模型使用体验

1、Cherry Studio 下载 官网下载地址:https://cherry-ai.com GitHub地址:https://github.com/kangfenmao/c2. 导入大模型IPA,开始使用 2.1 在线模型设置 在Cherry Studio中,可以接入自己使用的大语言模型API,点击设置,填入API密钥与API地址就可以。 下面以硅基流动为例进…

ATG1E BBQ Hard 学习笔记

ATG1E BBQ Hard 学习笔记 Luogu Link 题意简述 计算 $$\sum_{i=1}^n \sum_{j=i+1}^n \dbinom{a_i+b_i+a_j+b_j}{a_i+a_j}$$ 的值。答案对 \(10^9+7\) 取模。 \(N\le 2\times 10^5,a_i,b_i\le 2\times 10^3\)。 做法解析 \(O(N^2)\) 的做法是暴力枚举 \(i,j\),\(O(1)\) 计算出 …

【VMware vSphere】扩容或缩减 vCenter Server 的磁盘空间大小。

我们在部署 vCenter Server 时,根据不同环境的情况,可以选择不同的部署选项,比如环境中的主机可能运行了 100 个,或者虚拟机运行了 1000 个,此时按照官方推荐的选择“小型环境”部署选项即可满足需求;如果主机超过了 100 个,可能在 1000 个以内,或者虚拟机超过了 1000 …

day:3软件测试分类

一、按开发阶段划分 (1)单元测试 (2)集成测试 (3)系统测试 (4)集成测试 二、按查看代码分类 (1)黑盒测试 定义:是一种功能测试,测试中把测试的软件当成一个盒子,不关心盒子内部结构是什么,只关心软件的输入和输出。 例如:一个计算器,输入:1+1 输出:2,正确;…

活动管理神器来袭!板栗看板让你告别繁琐,拥抱高效

变革模型与项目管理工具的结合运用可以形成一个系统化、高效化的变革管理体系。通过明确变革需求与目标、执行变革计划、评估与反馈以及持续优化改进等步骤,可以确保变革的顺利实施和成功落地。项目管理中的变革模型是指一系列指导和管理组织内部变革过程的框架和方法。这些模…

劲爆!微信宣布接入 DeepSeek R1!!

大家好,我是R哥。 太劲爆了,连浓眉大眼的微信现在也接入了 DeepSeek,但还在还处于灰度测试阶段,入口比较隐蔽,要从搜索框下面的「AI 搜索」按钮进去。 如图所示:对于微信这么大一个国民级产品来说,在搜索领域引入 AI,肯定是看中了搜索入口的重要性,接入 DeepSeek 不仅…

懒人福音!一款基于 Go 实现的 Docker 终端管理工具!

lazydocker —— 一个基于 Go 编写实现的终端 Docker 管理 UI 工具,为用户提供了一种更直观、便捷的方式来管理 Docker 容器、镜像、数据卷、网络等资源。大家好,我是 Java陈序员。 之前给大家介绍一个在线的 Docker 可视化管理面板。 运维神器!Docker 可视化管理面板! 今天…

专利线框图绘制和导出,从Blender到3ds max

Blender软件设计3维的模型简单好用, 但是它生成的线框图线条太多,不符合专利要求,如下图: 我的方法是导出fbx格式模型,用下面教程里的方法生成线框图,最后用ps处理了一下, https://www.bilibili.com/video/BV1Bz421o7tq/?spm_id_from=333.337.search-card.all.click&a…