我正在使用从外部Web API站点(不同域)获取数据的Angular SPA(单页面应用程序)网站来尝试adal.js.通过adal.js,对SPA进行身份验证很容易,但是当需要承载令牌时,使其与API进行通信不会起作用.除了无数的博客之外,我已经使用了 https://github.com/AzureAD/azure-activedirectory-library-for-js作为模板.

问题是当我在启动adal.js时设置端点,adal.js似乎将所有出站端点流量重定向到microsofts登录服务.

观察:

> Adal.js会话存储包含两个adal.access.token.key条目.一个用于SPA Azure AD应用程序的客户端ID,另一个用于外部api.只有SPA令牌有一个值.
>如果我不注入$httpProvider到adal.js,那么调用去外部API,我得到一个401回报.
>如果我手动将SPA令牌添加到http头(授权:承载“令牌值”),我得到一个401返回.

我的理论是,adal.js无法为端点检索令牌(可能是因为我在SPA中配置了错误的东西),并且它阻止了端点的流量,因为它无法获取必需的令牌. SPA令牌不能用于API,因为它不包含所需的权限.为什么adal.js没有得到端点的令牌,我该如何解决?

附加信息:

>客户端Azure AD应用程序配置为在API中使用委托权限,并在应用程序清单中使用oauth2AllowImplicitFlow = true.
> API Azure AD应用程序配置为模拟,而oauth2AllowImplicitFlow = true(不要以为这是必需的,但尝试过).它是多租户.
> API被配置为允许所有CORS源代码,并且在使用模拟(混合MVC(Adal.net)Angular)的另一个Web应用程序使用时可以正常工作).

会话存储:

key (for the SPA application): adal.access.token.keyxxxxx-b7ab-4d1c-8cc8-xxx value: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1u...

key (for API application): adal.access.token.keyxxxxx-bae6-4760-b434-xxx
value:

app.js(Angular和adal配置文件)

(function () {
    'use strict';

    var app = angular.module('app',[
        // Angular modules 
        'ngRoute',// Custom modules 

        // 3rd Party Modules
        'AdalAngular'

    ]);

    app.config(['$routeProvider','$locationProvider',function ($routeProvider,$locationProvider) {
        $routeProvider           

            // route for the home page
            .when('/home',{
                templateUrl: 'App/Features/Test1/home.html',controller: 'home'
            })

            // route for the about page
            .when('/about',{
                templateUrl: 'App/Features/Test2/about.html',controller: 'about',requireADLogin: true
            })

            .otherwise({
                redirectTo: '/home'
            })

        //$locationProvider.html5Mode(true).hashPrefix('!');

        }]);

    app.config(['$httpProvider','adalAuthenticationServiceProvider',function ($httpProvider,adalAuthenticationServiceProvider) {
            // endpoint to resource mapping(optional)
            var endpoints = {
                "https://localhost/Api/": "xxx-bae6-4760-b434-xxx",};

            adalAuthenticationServiceProvider.init(
                    {                        
                        // Config to specify endpoints and similar for your app
                        clientId: "xxx-b7ab-4d1c-8cc8-xxx",// required
                        //localLoginUrl: "/login",// optional
                        //redirectUri : "your site",optional
                        extraQueryParameter: 'domain_hint=mydomain.com',endpoints: endpoints  // If you need to send CORS api requests.
                    },$httpProvider   // pass http provider to inject request interceptor to attach tokens
                    );
        }]);
})();

呼叫端点的角码:

$scope.getItems = function () {
            $http.get("https://localhost/Api/Items")
                .then(function (response) {                        
                    $scope.items = response.Items;
                });

解决方法

我不知道我们的设置是否完全一样,但我认为它是可比的.

我有一个Angular SPA,通过Azure API管理(APIM)使用外部Web API.我的代码可能不是最佳实践,但它对我来说至今为止:)

SPA Azure AD应用程序具有访问外部API Azure AD应用程序的授权.

SPA(基于Adal TodoList SPA sample)

app.js

adalProvider.init(
    {
        instance: 'https://login.microsoftonline.com/',tenant: 'mysecrettenant.onmicrosoft.com',clientId: '********-****-****-****-**********',//ClientId of the Azure AD app for my SPA app            
        extraQueryParameter: 'nux=1',cacheLocation: 'localStorage',// enable this for IE,as sessionStorage does not work for localhost.
    },$httpProvider
    );

来自todoListSvc.js的代码段

getWhoAmIBackend: function () {
        return $http.get('/api/Employee/GetWhoAmIBackend');
    },

来自EmployeeController的代码段

public string GetWhoAmIBackend()
    {
        try
        {
            AuthenticationResult result = GetAuthenticated();

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",result.Accesstoken);

            var request = new HttpRequestMessage()
            {
                RequestUri = new Uri(string.Format("{0}","https://api.mydomain.com/secretapi/api/Employees/GetWhoAmI")),Method = HttpMethod.Get,//This is the URL to my APIM endpoint,but you should be able to use a direct link to your external API

            };
            request.Headers.Add("Ocp-Apim-Trace","true"); //Not needed if you don't use APIM
            request.Headers.Add("Ocp-Apim-Subscription-Key","******mysecret subscriptionkey****"); //Not needed if you don't use APIM

            var response = client.SendAsync(request).Result;
            if (response.IsSuccessstatusCode)
            {
                var res = response.Content.ReadAsstringAsync().Result;
                return res;
            }
            return "No dice :(";
        }
        catch (Exception e)
        {
            if (e.InnerException != null)
                throw e.InnerException;
            throw e;
        }
    }

        private static AuthenticationResult GetAuthenticated()
    {
        BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
        var token = bootstrapContext.Token;

        Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext authContext =
            new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.microsoftonline.com/mysecrettenant.onmicrosoft.com");

        //The Client here is the SPA in Azure AD. The first param is the ClientId and the second is a key created in the Azure Portal for the AD App
        ClientCredential credential = new ClientCredential("clientid****-****","secretkey ********-****");

        //Get username from Claims
        string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;

        //Creating UserAssertion used for the "On-Behalf-Of" flow
        UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token,"urn:ietf:params:oauth:grant-type:jwt-bearer",userName);

        //Getting the token to talk to the external API
        var result = authContext.Acquiretoken("https://mysecrettenant.onmicrosoft.com/backendAPI",credential,userAssertion);
        return result;
    }

现在,在我的后端外部API中,我的Startup.Auth.cs如下所示:

外部API
Startup.Auth.cs

public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationoptions
            {
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],TokenValidationParameters = new TokenValidationParameters
                {
                    ValidAudience = ConfigurationManager.AppSettings["ida:Audience"],SaveSigninToken = true
                },AuthenticationType = "OAuth2Bearer"
            });
    }

如果这有帮助,或者我可以进一步的帮助,请通知我.

Adal.js没有获得外部api端点资源的令牌的更多相关文章

  1. HTML5 播放 RTSP 视频的实例代码

    目前大多数网络摄像头都是通过 RTSP 协议传输视频流的,但是 HTML 并不标准支持 RTSP 流。本文重点给大家介绍HTML5 播放 RTSP 视频的实例代码,需要的朋友参考下吧

  2. 利用Node实现HTML5离线存储的方法

    这篇文章主要介绍了利用Node实现HTML5离线存储的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 详解如何通过H5(浏览器/WebView/其他)唤起本地app

    这篇文章主要介绍了详解如何通过H5(浏览器/WebView/其他)唤起本地app的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. AmazeUI 折叠面板的实现代码

    这篇文章主要介绍了AmazeUI 折叠面板的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. HTML5之消息通知的使用(Web Notification)

    通知可以说是web中比较常见且重要的功能,私信、在线提问、或者一些在线即时通讯工具我们总是希望第一时间知道对方有了新的反馈。本篇文章主要介绍了HTML5之消息通知的使用(Web Notification),感兴趣的小伙伴们可以参考一下

  7. HTML5手指下滑弹出负一屏阻止移动端浏览器内置下拉刷新功能的实现代码

    这篇文章主要介绍了HTML5手指下滑弹出负一屏阻止移动端浏览器内置下拉刷新功能的实现代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  8. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. html5唤起app的方法

    这篇文章主要介绍了html5唤起app的方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. HTML5拍照和摄像机功能实战详解

    这篇文章主要介绍了HTML5拍照和摄像机功能实战详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部