使用 ADAL 通过 Angular 2 向 Dynamics CRM Web API 发出未经授权的 HTTP 请求 [英] Unauthorized HTTP request to Dynamics CRM Web API via Angular 2 using ADAL

查看:17
本文介绍了使用 ADAL 通过 Angular 2 向 Dynamics CRM Web API 发出未经授权的 HTTP 请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Angular 创建一个可以通过 Web API 连接到 Dynamics CRM 的应用程序.这些是我遵循的步骤:

1. 在 Azure 中注册本机应用程序,授予所需的委派权限并更新清单以允许隐式流.

2. 在 CRM 中创建了一个应用程序用户,将其应用程序 ID 设置为我的 Azure 注册应用程序的客户端 ID.为我的应用程序用户分配了一个自定义安全角色.

3. 克隆了许多 Angular 2 快速入门 Git 存储库,这些存储库通过 ADAL 向 Azure AD 进行身份验证,例如

上面写着:

请求的资源上不存在Access-Control-Allow-Origin"标头.因此,不允许访问 Origin 'http://localhost:3000'.响应具有 HTTP 状态代码 401.

查看我的 Chrome 浏览器的网络选项卡,我收到两个响应:

响应 1

常规

请求网址:https://ms-dyn365-prevxxxxxx/api/data/v8.2/accounts请求方法:选项状态码:200 OK远程地址:104.44.xxx.xxx:xxx推荐人政策:降级时无推荐人

标题

Access-Control-Allow-Headers:authentication,content-type,odata-maxversion,odata-version访问控制允许方法:GET访问控制允许来源:http://localhost:3000Access-Control-Expose-Headers:Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After访问控制最大年龄:3600内容长度:0日期:2017 年 4 月 13 日星期四 10:08:01 GMT服务器:Microsoft-IIS/8.5设置 Cookie:crmf5cookie=!NDyiupL55lrWWLtPQKTK52dwbxk9wdEAHeCiec0/z/7x9KWXe2dVIdQCGvL0S/HAp7F3N0OGfeWf/70=;安全;路径=/严格的传输安全性:max-age=31536000;包括子域变化:起源X-Powered-By:ASP.NET

响应 2

常规

请求网址:https://ms-dyn365-prevxxxxx.crm4.dynamics.com/api/data/v8.2/accounts请求方法:GET状态码:401 未授权远程地址:104.xx.xxx.xxx:xxx推荐人政策:降级时无推荐人

标题

缓存控制:私有内容长度:49内容类型:文本/html日期:2017 年 4 月 13 日星期四 10:08:01 GMTREQ_ID:b2be65bc-xxxx-4b34-xxxx-5c39812650xx服务器:Microsoft-IIS/8.5设置 Cookie:ReqClientId=xxxxxxxx-70b5-45f9-9b84-30f59481bxxx;到期=格林威治标准时间 2067 年 4 月 13 日星期三 10:08:01;路径=/;安全的;HttpOnly严格的传输安全性:max-age=31536000;包括子域WWW-Authenticate:Bearer authorization_uri=https://login.windows.net/xxxxxxxx-87e4-4d81-8010-xxxxxxxxxxxxx/oauth2/authorize,resource_id=https://ms-dyn365-prevxxxxxx.crm4.dynamics.com/X-Powered-By:ASP.NET

<小时>

注意:我可以通过 Postman 成功访问 Web API:

1.我在 Azure 中输入 https://www.getpostman.com/oauth2/callback 作为我的应用程序的回调 URL.

2.我打开Postman,设置参数如下,按Request Token:

令牌名称:令牌认证网址:https://login.windows.net/common/oauth2/authorize?resource=https://ms-dyn365-prevxxxxxx.crm4.dynamics.com访问令牌 URL:https://login.microsoftonline.com/common/oauth2/token客户端 ID:xxxxxxxx-ebd3-429c-9a95-xxxxxxxxxxxx回调地址:https://www.getpostman.com/oauth2/callback授权类型:授权码

3.这会打开一个我登录的网页.

4.返回一个令牌,我将其添加到 Postman GET 标头中:

内容类型:application/json授权:承载 eyJ0eXAiO...

5. 在 Postman 中发送 GET:

GET https://ms-dyn365-prevxxxxxx.crm4.dynamics.com/api/data/v8.2/accounts

6.帐户已成功返回.

如果我在我的应用程序中使用相同的令牌,我仍然会收到 401 错误.

解决方案

Access-Control-Allow-Origin表示问题是由跨域引起的.p>

通常,我们可以使用 JSONP 或在服务器上设置 Access-Control-Allow-Origin 标头.如果 JSONP 和 header 都无法设置,因为服务是第三方提供的,我们还可以创建一个服务代理,允许从特定的原始调用.

关于 AJAX 跨域问题的更多细节,你可以参考这个

附加代码demo进行测试:

<!DOCTYPE html><html><头><meta charset="utf-8"/><base href="/"><标题></标题><script src="node_modulesangularangular.js"></script></头><身体><div ng-app="myApp"><div ng-controller="HomeController"><ul class="nav navbar-nav navbar-right"><li><a class="btn btn-link" ng-click="listAccounts()">列出账户信息</a></li></ul><div ng-repeat="帐户中的帐户"><span>名称:</span><span>{{account.name}}</span></div></div></div><脚本>var myApp = angular.module('myApp',[]);myApp.controller('HomeController', ['$scope', '$http',函数($范围,$http){$scope.listAccounts=函数(){变量请求 = {方法:'GET',url: 'https://{domain}.crm.dynamics.com/api/data/v8.0/accounts',标题:{'授权': '承载 eyJ0eXAiO...'}};$http(req).then(函数(响应){$scope.accounts=response.data.value}, 功能(){});}}]);</脚本></身体></html>

附加 Angular 2 的测试代码示例:

https://github.com/VitorX/angular2-adaljs-crm

I'm trying to create an application using Angular that can connect to Dynamics CRM via the Web API. These are the steps I have followed:

1. Registered a native application in Azure, granted the required delegated permissions and updated the manifest to allow implicit flow.

2. Created an Application User in CRM, setting its Application ID equal to the Client ID of my Azure registered application. Assigned my Application User a custom Security Role.

3. Cloned many Angular 2 quickstart Git repositories which authenticate with Azure AD via ADAL such as this one.

4. Updated the cloned code's adal config, setting my tenant, clientId, redirectUri and endpoints.

So far this has been successful. I'm able to launch the application and login via my browser either as my Application User or a different CRM User which is a part of Azure AD. This returns a token.

5. Attempt to send an http.get to either v8.0 or v8.2 (I'm told that v8.2 does not support cross-domain calls):

getEntities(): Promise<any> {
    let token = this.adalService.getCachedToken(this.adalService.config.clientId);
    let headers = new Headers({
        'Authentication': 'Bearer ' + token,
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        'OData-MaxVersion': '4.0',
        'OData-Version': '4.0'
    });
    let options = new RequestOptions({ headers: headers });

    return this.http.get(`${crmURL}/api/data/v8.2/accounts`, options)
        .toPromise()
        .then((res) => { return res; })
        .catch((e) => { console.error(e); });
}

6. Receive this error message:

It reads:

No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://localhost:3000' is therefore not allowed access. 
The response had HTTP status code 401.

Looking at my Chrome browser's network tab, I receive two responses:

Response 1

General

Request URL:https://ms-dyn365-prevxxxxxx/api/data/v8.2/accounts
Request Method:OPTIONS
Status Code:200 OK
Remote Address:104.44.xxx.xxx:xxx
Referrer Policy:no-referrer-when-downgrade

Headers

Access-Control-Allow-Headers:authentication,content-type,odata-maxversion,odata-version
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:http://localhost:3000
Access-Control-Expose-Headers:Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After
Access-Control-Max-Age:3600
Content-Length:0
Date:Thu, 13 Apr 2017 10:08:01 GMT
Server:Microsoft-IIS/8.5
Set-Cookie:crmf5cookie=!NDyiupL55lrWWLtPQKTK52dwbxk9wdEAHeCiec0/z/7x9KWXe2dVIdQCGvL0S/HAp7F3N0OGfeWf/70=;secure; path=/
Strict-Transport-Security:max-age=31536000; includeSubDomains
Vary:Origin
X-Powered-By:ASP.NET

Response 2

General

Request URL:https://ms-dyn365-prevxxxxx.crm4.dynamics.com/api/data/v8.2/accounts
Request Method:GET
Status Code:401 Unauthorized
Remote Address:104.xx.xxx.xxx:xxx
Referrer Policy:no-referrer-when-downgrade

Headers

Cache-Control:private
Content-Length:49
Content-Type:text/html
Date:Thu, 13 Apr 2017 10:08:01 GMT
REQ_ID:b2be65bc-xxxx-4b34-xxxx-5c39812650xx
Server:Microsoft-IIS/8.5
Set-Cookie:ReqClientId=xxxxxxxx-70b5-45f9-9b84-30f59481bxxx; expires=Wed, 13-Apr-2067 10:08:01 GMT; path=/; secure; HttpOnly
Strict-Transport-Security:max-age=31536000; includeSubDomains
WWW-Authenticate:Bearer authorization_uri=https://login.windows.net/xxxxxxxx-87e4-4d81-8010-xxxxxxxxxxxxx/oauth2/authorize, resource_id=https://ms-dyn365-prevxxxxxx.crm4.dynamics.com/
X-Powered-By:ASP.NET


Note: I am able to successfully access the Web API via Postman:

1. I enter https://www.getpostman.com/oauth2/callback as a Callback URL in Azure for my Application.

2. I open Postman, set the parameters as follows and press Request Token:

Token Name: Token
Auth URL: https://login.windows.net/common/oauth2/authorize?resource=https://ms-dyn365-prevxxxxxx.crm4.dynamics.com
Access Token URL: https://login.microsoftonline.com/common/oauth2/token
Client ID: xxxxxxxx-ebd3-429c-9a95-xxxxxxxxxxxx
Callback URL: https://www.getpostman.com/oauth2/callback
Grant Type: Authorization Code

3. This opens a web page in which I login.

4. A token is returned which I add to a Postman GET header:

Content-Type: application/json
Authorization: Bearer eyJ0eXAiO...

5. Send a GET in Postman:

GET https://ms-dyn365-prevxxxxxx.crm4.dynamics.com/api/data/v8.2/accounts

6. Accounts are successfully returned.

If I use the same token within my Application I still receive a 401 error.

解决方案

The Access-Control-Allow-Origin indicates the issue is caused by cross domain.

Normally, we can use JSONP or set Access-Control-Allow-Origin header on the server. And if both JSONP and header is not able to set since the service is provider by the third-party, we can also create a service proxy which enable to allow called from the specific orignal.

More detail about the AJAX cross domain issue, you can refer this thread.

Update

After the further investigation, the issue is a server-side issue which relative to the specific version of REST requesting.

The 8.2 version of REST doesn't support cross domain at present. As a workaround we can use 8.0 which works well for me like the figure below:

Append the code demo to test:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <base href="/">
    <title></title>
    <script src="node_modulesangularangular.js"></script>

</head>
<body>
    <div ng-app="myApp">
        <div ng-controller="HomeController">
            <ul class="nav navbar-nav navbar-right">            
                     <li><a class="btn btn-link" ng-click="listAccounts()">List account info</a></li>
            </ul>
           <div ng-repeat="account in accounts">
                    <span>name:</span><span>{{account.name}}</span>
           </div>
        </div>
    </div>

    <script>
    var myApp = angular.module('myApp',[]);

    myApp.controller('HomeController', ['$scope', '$http',
                            function ($scope, $http){

                                    $scope.listAccounts=function(){

                                        var req = {
                                        method: 'GET',
                                        url: 'https://{domain}.crm.dynamics.com/api/data/v8.0/accounts',
                                        headers: {
                                        'authorization': 'Bearer eyJ0eXAiO...'
                                        }
                                        };
                                       $http(req).then(function(response){
                                            $scope.accounts=response.data.value
                                       }, function(){

                                       });
                                    }
                            }]);
    </script>
</body>
</html>

Append test code sample for Angular 2:

https://github.com/VitorX/angular2-adaljs-crm

这篇关于使用 ADAL 通过 Angular 2 向 Dynamics CRM Web API 发出未经授权的 HTTP 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆