发布日期: 2017年1月
适用于: Dynamics 365 (online),Dynamics 365 (on-premises),Dynamics CRM 2016,Dynamics CRM Online
此演练介绍使用 adal.js 和跨源资源共享 (CORS) 注册和配置最简单的单页应用程序 (SPA) 以访问 Microsoft Dynamics CRM Online 2016 更新 中的数据的流程。详细信息:使用 OAuth 和跨源资源共享将单页应用程序连接到 Microsoft Dynamics 365。
必备项
Microsoft Dynamics CRM Online 2016 更新
您必须拥有具有 Microsoft Office 365 管理员角色的 Microsoft Dynamics 365 (online) 系统用户帐户。
用于应用程序注册的 Microsoft Azure 订阅。 试用版帐户也将运行。
Microsoft Visual Studio 2015
本演练的目标
完成此演练后,您将可以在 Visual Studio 中运行简单的 SPA 应用程序,用户可通过该应用程序执行身份验证和从 Microsoft Dynamics 365 (online) 检索数据。 此应用程序由一个 HTML 页面构成。
首次调试此应用程序时,只有一个“登录”按钮。
单击“登录”,这样将把您重定向到登录页以输入您的凭据。
输入凭据之后,将把您定向回 HTML 页面,可在此处找到隐藏的“登录”按钮,并显示“注销”按钮和“获取客户”按钮。 还将看到您的用户帐户欢迎您使用您的信息。
单击“获取客户”按钮将从您的 Microsoft Dynamics 365 组织检索 10 条客户记录。 “获取客户”按钮已禁用,如下面的屏幕截图所示:
.jpeg)
备注
首次从 Microsoft Dynamics 365 加载数据的速度可能非常低,因为需要执行为身份验证提供支持的操作,但是后续操作就快得多。
最后,可以单击“注销”按钮注销。
备注
此 SPA 应用程序不应提供用于开发强大的 SPA 应用程序的模式。 它经过简化,专注于注册和配置应用程序的过程。
创建 Web 应用程序项目
可通过使用 Microsoft Visual Studio 2015 创建新的“ASP.NET Web 应用程序”项目和使用“空”模板。 可以按照您的喜好为项目命名。
您应该也可以使用 Microsoft Visual Studio 的早期版本,但是这些步骤将介绍如何使用 Visual Studio 2015。
向项目添加一个名称为 SimpleSPA.html 的 HTML 页面并粘贴以下代码:
<!DOCTYPE html> <html> <head> <title>Simple SPA</title> <meta charset="utf-8" /> <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script> <script type="text/javascript"> "use strict"; //Set these variables to match your environment var organizationURI = "https:// [organization name].crm.dynamics.com"; //The URL to connect to CRM (online) var tenant = "[xxx.onmicrosoft.com]"; //The name of the Azure AD organization you use var clientId = "[client id]"; //The ClientId you got when you registered the application var pageUrl = "https://localhost: [PORT #]/SimpleSPA.html"; //The URL of this page in your development environment when debugging. var user, authContext, message, errorMessage, loginButton, logoutButton, getAccountsButton, accountsTable, accountsTableBody; //Configuration data for AuthenticationContext var endpoints = { orgUri: organizationURI }; window.config = { tenant: tenant, clientId: clientId, postLogoutRedirectUri: pageUrl, endpoints: endpoints, cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost. }; document.onreadystatechange = function () { if (document.readyState == "complete") { //Set DOM elements referenced by scripts message = document.getElementById("message"); errorMessage = document.getElementById("errorMessage"); loginButton = document.getElementById("login"); logoutButton = document.getElementById("logout"); getAccountsButton = document.getElementById("getAccounts"); accountsTable = document.getElementById("accountsTable"); accountsTableBody = document.getElementById("accountsTableBody"); //Event handlers on DOM elements loginButton.addEventListener("click", login); logoutButton.addEventListener("click", logout); getAccountsButton.addEventListener("click", getAccounts); //call authentication function authenticate(); if (user) { loginButton.style.display = "none"; logoutButton.style.display = "block"; getAccountsButton.style.display = "block"; var helloMessage = document.createElement("p"); helloMessage.textContent = "Hello " + user.profile.name; message.appendChild(helloMessage) } else { loginButton.style.display = "block"; logoutButton.style.display = "none"; getAccountsButton.style.display = "none"; } } } // Function that manages authentication function authenticate() { //OAuth context authContext = new AuthenticationContext(config); // Check For & Handle Redirect From AAD After Login var isCallback = authContext.isCallback(window.location.hash); if (isCallback) { authContext.handleWindowCallback(); } var loginError = authContext.getLoginError(); if (isCallback && !loginError) { window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST); } else { errorMessage.textContent = loginError; } user = authContext.getCachedUser(); } //function that logs in the user function login() { authContext.login(); } //function that logs out the user function logout() { authContext.logOut(); accountsTable.style.display = "none"; accountsTableBody.innerHTML = ""; } //function that initiates retrieval of accounts function getAccounts() { getAccountsButton.disabled = true; var retrievingAccountsMessage = document.createElement("p"); retrievingAccountsMessage.textContent = "Retrieving 10 accounts from " + organizationURI + "/api/data/v8.0/accounts"; message.appendChild(retrievingAccountsMessage) // Function to perform operation is passed as a parameter to the aquireToken method authContext.acquireToken(organizationURI, retrieveAccounts) } //Function that actually retrieves the accounts function retrieveAccounts(error, token) { // Handle ADAL Errors. if (error || !token) { errorMessage.textContent = 'ADAL error occurred: ' + error; return; } var req = new XMLHttpRequest() req.open("GET", encodeURI(organizationURI + "/api/data/v8.0/accounts?$select=name,address1_city&$top=10"), true); //Set Bearer token req.setRequestHeader("Authorization", "Bearer " + token); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { req.onreadystatechange = null; if (this.status == 200) { var accounts = JSON.parse(this.response).value; renderAccounts(accounts); } else { var error = JSON.parse(this.response).error; console.log(error.message); errorMessage.textContent = error.message; } } }; req.send(); } //Function that writes account data to the accountsTable function renderAccounts(accounts) { accounts.forEach(function (account) { var name = account.name; var city = account.address1_city; var nameCell = document.createElement("td"); nameCell.textContent = name; var cityCell = document.createElement("td"); cityCell.textContent = city; var row = document.createElement("tr"); row.appendChild(nameCell); row.appendChild(cityCell); accountsTableBody.appendChild(row); }); accountsTable.style.display = "block"; } </script> <style> body { font-family: 'Segoe UI'; } table { border-collapse: collapse; } td, th { border: 1px solid black; } #errorMessage { color: red; } #message { color: green; } </style> </head> <body> <button id="login">Login</button> <button id="logout" style="display:none;">Logout</button> <button id="getAccounts" style="display:none;">Get Accounts</button> <div id="errorMessage"></div> <div id="message"></div> <table id="accountsTable" style="display:none;"> <thead><tr><th>Name</th><th>City</th></tr></thead> <tbody id="accountsTableBody"></tbody> </table> </body> </html>将此页面设置为项目的起始页
在项目的属性中,选择“服务器”下的“Web”,而不是选择“项目 URL”。 应该类似 https://localhost:46575/。 记下生成的端口号。 您将在下一步中需要使用此信息。
在 SimpleSPA.html 页面内,找到以下配置变量并相应设置。 完成演练的下一部分之后,您就可以设置 clientId。
//Set these variables to match your environment var organizationURI = "https://[organization name].crm.dynamics.com"; //The URL to connect to CRM (online) var tenant = "[xxx.onmicrosoft.com]"; //The name of the Azure AD organization you use var clientId = "[client id]"; //The ClientId you got when you registered the application var pageUrl = "https://localhost:[PORT #]/SimpleSPA.html"; //The URL of this page in your development environment when debugging.
注册应用程序
通过使用具有管理员权限的帐户,登录 到 Microsoft Azure 管理门户。 必须使用与您要注册的应用程序相同的 Office 365 订阅(租户)中使用账户。 还可以通过 Office 365 管理员中心来访问 Microsoft Azure 门户,方法是展开左侧导航窗格中的”ADMIN“项目并选择”Azure AD“。
如果您不具有 Azure 租户(帐户)或者您有但在您的 Azure 订阅中没有含 Microsoft Dynamics 365 (online) 的 Office 365 订阅,则按照主题为您的开发人员网站设置 Azure Active Directory 访问中的说明关联这两个帐户。
如果没有客户,您可以使用信用卡注册客户。 但是,如果只按照本主题调用的程序注册一个或多个应用程序,那么客户将是免费用于应用程序注册,并且不会从信用卡中收取费用。详细信息:动态目录定价详细信息
在页面左列,单击“Active Directory”。 您可能需要滚动到左列查看“动态目录”图标和标签。
单击目录列表中所需的租户目录。
.jpeg)
如果您的 Dynamics 365 租户目录在目录列表中未显示,请单击“添加”,然后在对话框中选择“使用现有目录”。 按照提供的提示和说明,然后返回到步骤 1。.
使用选择的目标目录,单击“应用程序”(靠近页面顶部),然后单击“添加”。
在”您想做什么?“对话中框中,单击“添加我的组织正在开发的应用程序”。
出现提示时,请输入您的应用程序的名称(如“SimpleSPA”),选择类型(“Web 应用程序”和/或“Web API“),然后单击向右箭头键继续。 单击问号”?“了解每个输入字段的相应值的详细信息。
输入以下信息:
登录 URL
这是用户在登录后应重定向到的 URL。 出于 Visual Studio 中的调试目的,它应该是 https://localhost:####/SimpleSPA.html,其中 #### 表示您从创建 Web 应用程序项目过程的步骤 4 获取的端口号。应用 ID URI
这必须是应用程序的唯一标识符。 使用 https://XXXX.onmicrosoft.com/SimpleSPA,其中 XXXX 是 Active Directory 租户。
在选中新注册应用程序的选项卡之后,单击“配置”,找到“客户端 ID”,然后复制该 ID。
将 SimpleSPA.html 页面中的 clientId 变量设置为此值。 参考创建 Web 应用程序项目过程的步骤 5。
滚动到页面底部,然后单击“添加应用程序”。 在对话框中选择“Dynamics 365 Online”,然后关闭对话框。
在其他应用程序的权限下,将找到“Dynamics 365 Online”和“委托的权限: 0”的行。 将其选中,然后单击“将 Dynamics 365(在线)作为组织用户添加”.
保存应用程序注册信息
在底部,选择“管理”清单,然后选择“下载清单”。
打开下载的 JSON 文件,然后找到 "oauth2AllowImplicitFlow": false, 行并将 false 更改为 true,然后保存文件。
再次返回“管理清单”。 选择“上载清单”并上载刚才保存的 JSON 文件。
调试应用程序
将浏览器设置为 Microsoft Edge、Google Chrome 或 Mozilla Firefox。
备注
这种情况下,Internet Explorer 不能用于调试。
按 F5 键开始调试。 应该出现 本演练的目标 中介绍的行为。
如果未获得预期结果,请双击在注册应用程序和配置 SimpleSPA.html 代码时设置的值。
另请参阅
使用 OAuth 和跨源资源共享将单页应用程序连接到 Microsoft Dynamics 365
Microsoft Dynamics 365
© 2017 Microsoft。 保留所有权利。 版权