【问题标题】:Unauthorized request in Sharepoint API with MSAL tokenSharepoint API 中带有 MSAL 令牌的未经授权的请求
【发布时间】:2020-02-13 08:36:08
【问题描述】:

背景 我正在开发一个使用 Azure Active Directory(Microsoft 身份验证)进行身份验证的移动应用程序,并且可以访问 Sharepoint 中的一些信息。我的第一选择是使用 Ionic Cordova,但似乎不支持 Cordova-MSAL 集成。所以我们选择了 Xamarin,以开发一个跨平台的应用程序,但兼容 Microsoft 身份验证。

情况 我正在尝试连接 Sharepoint API。

1- 我在 Azure (Active Directory) 中注册了一个新应用,并且 给定的权限。

2- 我正在使用 MSAL 获取不记名令牌 库(在 web 和 Xamarin 中),在我自己登录后(比如在 下面的链接): https://docs.microsoft.com/es-es/azure/active-directory/develop/quickstart-v2-javascript

3- 现在我向 Sharepoint API 发出以下请求。

url: http://site url/_api/web/lists(guid'list GUID'),
method: GET
Headers:
    Authorization: "Bearer " + accessToken
    accept: "application/json;odata=verbose" 

但我总是收到以下错误:

{"error_description":"Invalid JWT token. No certificate thumbprint specified in token header."}

我读到很多人谈论 MSAL 的错误,但这是官方的方式(ADAL 看起来即将被弃用)。

任何想法将不胜感激,非常感谢。

【问题讨论】:

    标签: azure sharepoint active-directory azure-active-directory msal


    【解决方案1】:

    令牌无效,请检查您获取访问令牌的方式。我授予了AllSites.FullControl 对该应用程序的权限。所以范围应该是

    https://{xxx}.sharepoint.com/AllSites.FullControl
    

    回应:

    【讨论】:

    • 您能否确认使用此生成的令牌可以访问共享点数据?
    • 您能否提供您生成令牌的参考链接以及哪个身份验证流程?
    • @anomepani 我使用了代码授权流程docs.microsoft.com/en-us/azure/active-directory/develop/…
    • @anomepani 令牌拥有AllSites.FullControl 权限。
    • 即使令牌中没有有效受众的令牌权限,它也不会起作用。
    【解决方案2】:

    在使用 MSAL.js 进行身份验证并获取访问令牌以成功调用 SharePoint Online API 时,我也遇到了这个问题。

    以下来自 Microsoft 的文档提供了一个很棒的示例和通过 MSAL 进行身份验证的说明:https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-spa

    但是,我需要继续利用获得的令牌直接调用 SharePoint API,而不是通过 Graph API 使用服务。

    为了解决这个问题,我必须如下定义我的范围:

    scopes: [https://{tenantName}.sharepoint.com/.default]
    

    使用 Microsoft 文章中的示例,我进行了必要的更改。我能够利用获取的访问令牌成功调用 SharePoint API:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Quickstart for MSAL JS</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.4/bluebird.min.js"></script>
        <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/msal.js"> 
    </script>
    </head>
    <body>
        <h2>Welcome to MSAL.js Quickstart</h2><br />
        <h4 id="WelcomeMessage"></h4>
        <button id="SignIn" onclick="signIn()">Sign In</button><br /><br />
        <pre id="json"></pre>
        <script>
    
        var msalConfig = {
            auth: {
                clientId: "{clientID}",
                authority: "https://login.microsoftonline.com/organizations"
            },
            cache: {
                cacheLocation: "localStorage",
                storeAuthStateInCookie: true
            }
        };
    
        var sharePointConfig = {
            sharePointFileEndpoint: "https://{tenantName}.sharepoint.com/sites/{siteName}/_api/web/GetFolderByServerRelativeUrl('Shared Documents/{folderName}')/Files('testFile.txt')/$value"
        }
    
        //the defined scopes were updated for making calls to the SharePoint API.
    
        var requestObj = {
            scopes: ["https://{tenantName}.sharepoint.com/.default"]
        };
    
        var myMSALObj = new Msal.UserAgentApplication(msalConfig);
        // Register Callbacks for redirect flow
        myMSALObj.handleRedirectCallback(authRedirectCallBack);
    
    
        function signIn() {
    
            myMSALObj.loginPopup(requestObj).then(function (loginResponse) {
                //Login Success
                showWelcomeMessage();
                acquireTokenPopupAndCallAPI();
    
            }).catch(function (error) {
                console.log(error);
            });
        }
    
    
        function acquireTokenPopupAndCallAPI() {
            //Always start with acquireTokenSilent to obtain a token in the signed in user from cache
            myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
    
                //Http Request
    
                callAPI(sharePointConfig.sharePointFileEndpoint, tokenResponse.accessToken, graphAPICallback);
    
            }).catch(function (error) {
                console.log(error);
                // Upon acquireTokenSilent failure (due to consent or interaction or login required ONLY)
                // Call acquireTokenPopup(popup window)
                if (requiresInteraction(error.errorCode)) {
                    myMSALObj.acquireTokenPopup(requestObj).then(function (tokenResponse) {
    
                        //Http Request
    
                        callAPI(sharePointConfig.sharePointFileEndpoint, tokenResponse.accessToken, graphAPICallback);
    
                    }).catch(function (error) {
                        console.log(error);
                    });
                }
            });
        }
    
    
        function graphAPICallback(data) {
            document.getElementById("json").innerHTML = JSON.stringify(data, null, 2);
        }
    
    
        function showWelcomeMessage() {
            var divWelcome = document.getElementById('WelcomeMessage');
            divWelcome.innerHTML = 'Welcome ' + myMSALObj.getAccount().userName + "to Microsoft Graph API";
            var loginbutton = document.getElementById('SignIn');
            loginbutton.innerHTML = 'Sign Out';
            loginbutton.setAttribute('onclick', 'signOut();');
        }
    
        function authRedirectCallBack(error, response) {
            if (error) {
                console.log(error);
            }
            else {
                if (response.tokenType === "access_token") {
    
                    callAPI(sharePointConfig.sharePointFileEndpoint, tokenResponse.accessToken, graphAPICallback);
                } else {
                    console.log("token type is:" + response.tokenType);
                }
            }
        }
    
        function requiresInteraction(errorCode) {
            if (!errorCode || !errorCode.length) {
                return false;
            }
            return errorCode === "consent_required" ||
                errorCode === "interaction_required" ||
                errorCode === "login_required";
        }
    
        // Browser check variables
        var ua = window.navigator.userAgent;
        var msie = ua.indexOf('MSIE ');
        var msie11 = ua.indexOf('Trident/');
        var msedge = ua.indexOf('Edge/');
        var isIE = msie > 0 || msie11 > 0;
        var isEdge = msedge > 0;
        //If you support IE, our recommendation is that you sign-in using Redirect APIs
        //If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check
        // can change this to default an experience outside browser use
        var loginType = isIE ? "REDIRECT" : "POPUP";
    
        if (loginType === 'POPUP') {
            if (myMSALObj.getAccount()) {// avoid duplicate code execution on page load in case of iframe and popup window.
                showWelcomeMessage();
                acquireTokenPopupAndCallAPI();
            }
        }
        else if (loginType === 'REDIRECT') {
            document.getElementById("SignIn").onclick = function () {
                myMSALObj.loginRedirect(requestObj);
            };
            if (myMSALObj.getAccount() && !myMSALObj.isCallback(window.location.hash)) {// avoid duplicate code execution on page load in case of iframe and popup window.
                showWelcomeMessage();
                acquireTokenPopupAndCallAPI();
            }
        } else {
            console.error('Please set a valid login type');
        }
    
    
        function callAPI(theUrl, accessToken, callback) {
            var xmlHttp = new XMLHttpRequest();
            /*
            xmlHttp.onreadystatechange = function () {
                if (this.readyState == 4 && this.status == 200)
                    callback(JSON.parse(this.responseText));
            }
            */
            xmlHttp.open("GET", theUrl, true); // true for asynchronous
            xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
            xmlHttp.send();         
        }
    
    
        function signOut() {
            myMSALObj.logout();
        }
    
    </script>
    </body>
    </html>
    

    以上示例是 Microsoft 示例的修改版本。我能够利用它进行成功的测试。

    【讨论】:

      猜你喜欢
      • 2017-07-06
      • 2011-11-16
      • 1970-01-01
      • 2021-09-12
      • 2017-10-16
      • 1970-01-01
      • 2019-08-07
      • 2012-12-04
      • 2017-06-12
      相关资源
      最近更新 更多