如何通过Dynamics 365 Web API为外部调研页面拉取工单关联的用户与公司信息
实现方案(外部独立页面拉取Dynamics 365 Online数据)
Dynamics 365 Web API默认不允许跨域匿名调用,你找到的CRM内部Web资源教程是因为共享了上下文鉴权,外部页面必须走Azure AD客户端凭据鉴权流程,用你现有的PHP后端做代理调用规避前端跨域问题,具体实现步骤如下:
1. 前置配置(Azure AD侧和Dynamics 365侧)
- 登录Azure Portal,注册新的应用注册,不需要配置重定向URI(因为使用客户端凭据流)
- 注册完成后记录3个值:
客户端ID(Application ID)、租户ID(Tenant ID),再进入「证书和密码」页面新建客户端密码,记录密码值(仅显示一次,注意保存) - 进入Dynamics 365 Online的「高级设置-安全-用户」,新建一个应用用户,绑定刚才注册的Azure AD应用的客户端ID,给这个用户分配工单实体的读取权限,以及关联的客户、联系人实体的读取权限
2. 后端(PHP侧)代理实现
前端直接调用Dynamics API会触发跨域限制,所有API请求走PHP后端转发:
2.1 获取Dynamics 365鉴权Access Token
// 配置参数替换为你自己的实际值 $tenantId = '你的Azure AD租户ID'; $clientId = '注册应用的客户端ID'; $clientSecret = '注册应用的客户端密码'; $dynamicsUrl = '你的Dynamics 365实例URL,例如https://xxx.crm.dynamics.com'; // 请求获取Access Token $tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/token"; $postData = [ 'grant_type' => 'client_credentials', 'client_id' => $clientId, 'client_secret' => $clientSecret, 'resource' => $dynamicsUrl ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $tokenUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $tokenResponse = json_decode(curl_exec($ch), true); $accessToken = $tokenResponse['access_token'];
2.2 调用Dynamics Web API拉取工单关联数据
以下示例默认使用Dynamics 365原生工单实体逻辑名incident,如果是自定义实体、自定义字段需要替换为你系统内的实际逻辑名:
// 从前端获取URL传递的工单编号 $ticketNumber = $_GET['ticket_number']; // 构造Web API查询语句,按工单编号过滤,返回关联的联系人姓名、所属企业名称 $apiUrl = "$dynamicsUrl/api/data/v9.2/incidents?" ."\$filter=ticketnumber eq '$ticketNumber'" ."&\$select=incidentid" ."&\$expand=customerid(\$select=fullname,name)"; // 发起API请求 curl_setopt($ch, CURLOPT_URL, $apiUrl); curl_setopt($ch, CURLOPT_HTTPGET, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer $accessToken", "OData-MaxVersion: 4.0", "OData-Version: 4.0", "Accept: application/json" ]); $apiResponse = json_decode(curl_exec($ch), true); curl_close($ch); // 处理返回结果返回给前端 if(!empty($apiResponse['value'])) { $ticketData = $apiResponse['value'][0]; $result = [ 'user_name' => $ticketData['customerid']['fullname'] ?? '', 'company_name' => $ticketData['customerid']['name'] ?? '' ]; echo json_encode(['code' => 200, 'data' => $result]); } else { echo json_encode(['code' => 404, 'msg' => '未找到对应工单']); }
3. 前端JS调用
前端直接调用自己的PHP代理接口即可,不需要直接对接Dynamics 365:
// 从URL参数获取工单编号 function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i=0;i<vars.length;i++) { var pair = vars[i].split("="); if(pair[0] == variable) return pair[1]; } return false; } const ticketNumber = getQueryVariable('ticket_id'); // 调用PHP后端接口拉取数据 fetch(`/你的PHP代理文件路径.php?ticket_number=${encodeURIComponent(ticketNumber)}`) .then(res => res.json()) .then(res => { if(res.code === 200) { // 把获取到的姓名、企业名称填充到页面对应位置 document.getElementById('user_name').textContent = res.data.user_name; document.getElementById('company_name').textContent = res.data.company_name; } else { alert(res.msg); } })
注意事项
- 实体和字段的逻辑名称可以在Dynamics 365的自定义实体设置页查看,有自定义字段的话需要替换代码里的对应字段名
- 可以对获取到的Access Token做本地缓存,默认有效期1小时,避免每次请求都重新获取Token,提升接口性能
- 生产环境要对前端传递的工单编号做参数校验,避免注入类风险
内容的提问来源于stack exchange,提问作者Nick Peterson
相关产品推荐
相关产品推荐

