ADAL JS 在调用 WebAPI 时不附加用户令牌

ADAL JS not attaching user token while invoking WebApi

本文关键字:用户 令牌 JS 调用 WebAPI ADAL      更新时间:2023-09-26

我正在使用ADAL JS针对Azure AD对用户进行身份验证。由于我是ADAL JS新手,我开始阅读以下文章,我觉得这些信息非常丰富:

  • 介绍 ADAL JS v1
  • ADAL JavaScript 和 AngularJS – Deep Dive

阅读文章后,我的印象是ADAL JS拦截服务调用,如果服务 url 注册为AuthenticationContext配置中的终结点之一,它会将 JWT 令牌附加为身份验证持有者信息。

但是,我发现在我的案例中并没有发生同样的情况。经过一番挖掘,在我看来,只有在同时使用adal-angular对应部分的情况下才有可能,而我目前没有使用,仅仅是因为我的 Web 应用程序不是基于 Angular。

请让我知道我的理解是否正确。如果我需要显式添加持有者信息,也可以这样做,但我更关心我是否缺少一些开箱即用的功能。

其他详细信息:我目前的配置如下所示:

private endpoints: any = {
    "https://myhost/api": "here_goes_client_id"
}
...
private config: any;
private authContext: any = undefined;
....
this.config = {
    tenant: "my_tenant.onmicrosoft.com",
    clientId: "client_id_of_app_in_tenant_ad",
    postLogoutRedirectUri: window.location.origin,
    cacheLocation: "sessionStorage",
    endpoints: this.endpoints
};
this.authContext = new (window["AuthenticationContext"])(this.config);

同样在服务器端(WebApi),身份验证配置(Startup.Auth)如下所示:

public void ConfigureOAuth(IAppBuilder app, HttpConfiguration httpConfig)
{
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
        new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        {
            Tenant = "my_tenant.onmicrosoft.com",
            TokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience = "client_id_of_app_in_tenant_ad"
            }
         });
}

但是,Authorizationrequest.Headers 中始终为空。

更新:似乎这同样适用于代币的自动续订; 当与adal-angular结合使用时,令牌的续订通过在引擎盖下调用AuthenticationContext.acquireToken(resource, callback)无缝工作。如果我错了,请纠正我。

阅读文章后,我的印象是 ADAL JS 会拦截服务调用,如果服务 URL 在 AuthenticationContext 配置中注册为终结点之一,它会将 JWT 令牌附加为身份验证持有者信息。

仅当您的应用程序是基于角度的时,这才有效。正如你提到的,这个逻辑存在于adal-angular中。

但是,如果你想坚持使用纯JS,你将无法获得自动的"get-access-token-and-attach-it-to-header"支持。可以使用acquireToken(resource, callback API 获取终结点的令牌。但是,您必须在将请求发送到 API 的控制器中执行一些工作。

这可能会给你一些想法:https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi/blob/master/TodoSPA/App/Scripts/Ctrls/todoListCtrl.js。此示例不使用角度。

ADAL.JS 与 v2.0 隐式流不兼容。我无法让它工作,因为我最近设置了我的项目,并且不认为项目是向后兼容的。

这非常令人困惑,花了很长时间才弄清楚我混淆了版本,并且不能将 ADAL.JS 与 v2.0 一起使用。一旦我删除它,事情就顺利多了,只是做了几个 XHR 请求和一个弹出窗口,实际上不需要魔法!

下面是 v2 的代码:

function testNoADAL() {
    var clientId = "..guid..";
    var redirectUrl = "..your one.."
    var authServer = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?";
    var responseType = "token";
    var stateParam = Math.random() * new Date().getTime();
    var authUrl = authServer +
                                "response_type=" + encodeURI(responseType) +
                                "&client_id=" + encodeURI(clientId) +
                                "&scope=" + encodeURI("https://outlook.office.com/Mail.ReadWrite") +
                                "&redirect_uri=" + encodeURI(redirectUrl) +
                                "&state=" + stateParam;
    var popupWindow = window.open(authUrl, "Login", 'width=' + 300 + ', height=' + 600 + ', top=' + 10 + ', left=' + 10 + ',location=no,toolbar=yes');
    if (popupWindow.focus) {
        popupWindow.focus();
    }
}

注意:重定向URL会出现在弹出窗口中,需要有代码才能传递位置哈希,例如:

<script>window.opener.processMicrosoftAuthResultUrl(location.hash);window.close();</script>

function processMicrosoftAuthResultUrl(hash) {
    if (hash.indexOf("#") == 0) {
        hash = hash.substr(1);
    }
    var obj = getUrlParameters(hash);
    if (obj.error) {
        if (obj.error == "invalid_resource") {
            errorDialog("Your Office 365 needs to be configured to enable access to Outlook Mail.");
        } else {
            errorDialog("ADAL: " + obj.error_description);
        }
    } else {
        if (obj.access_token) {
            console.log("ADAL got access token!");
            var token = obj.access_token;
            var url = "https://outlook.office.com/api/v2.0/me/MailFolders/Inbox/messages";
            $.ajax({
                type: "GET",
                url: url,
                headers: {
                    'Authorization': 'Bearer ' + token,
                },
            }).done(function (data) {
                console.log("got data!", data);
                var message = "Your latest email is: " + data.value[0].Subject + " from " + data.value[0].From.EmailAddress.Name+ " on " + df_FmtDateTime(new Date(data.value[0].ReceivedDateTime));
                alertDialog(message);
            }).fail(function () {
                console.error('Error getting todo list data')
            });
        }
    }
}
function getUrlParameters(url) {
    // get querystring and turn it into an object
    if (!url) return {};
    if (url.indexOf("?") > -1) {
        url = url.split("?")[1];
    }
    if (url.indexOf("#") > -1) {
        url = url.split("#")[0];
    }
    if (!url) return {};
    url = url.split('&')
    var b = {};
    for (var i = 0; i < url.length; ++i) {
        var p = url[i].split('=', 2);
        if (p.length == 1) {
            b[p[0]] = "";
        } else {
            b[decodeURIComponent(p[0])] = decodeURIComponent(p[1].replace(/'+/g, " "));
        }
    }
    return b;
}