您可以在JavaScript中使用Microsoft Graph API来获取列表项吗?

时间:2019-05-24 22:12:37

标签: javascript microsoft-graph sharepoint-online

我正在使用MSAL样本,并将其转换为使用MS Graph读取SharePoint,但是当涉及到读取列表项时,似乎遇到了权限问题。

为确保语法正确,我将Graph Explorer和AD帐户一起使用,并且能够读取列表项并确认URI正确。我也能够阅读并获得一系列列表。但是,只要我尝试获取列表的列表项,就不会返回任何内容。

基本代码在https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-spa

这是我从示例中转换的代码。如果更新变量并在Azure中注册,则应该可以在SPO网站上运行。

<!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 />
    <button id="btnAllLists" onclick="GetWithEndPoint()">Get All Lists</button><br /><br />
    <button id="btnListItems" onclick="GetWithEndPoint()">Get List Items</button><br /><br />
    <button id="btnListItemsAllFields" onclick="GetWithEndPoint()">Get List Items All Fields</button><br /><br />
    <pre id="json"></pre>
    <script>
        var config = {
            portalname: "yourportalname",
            sitename: "yoursitename",
            listid: "guidofalist"
        }
        var msalConfig = {
            auth: {
                clientId: "azureclientguid",
                authority: "https://login.microsoftonline.com/yourportal.onmicrosoft.com"
            },
            cache: {
                cacheLocation: "localStorage",
                storeAuthStateInCookie: true
            }
        };
        var graphConfig = {
            graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
            spShowAllListsEp: "https://graph.microsoft.com/v1.0/sites/" + config.portalname + ".sharepoint.com:/sites/" + config.sitename + ":/lists",
            spShowListItemsEp: "https://graph.microsoft.com/v1.0/sites/" + config.portalname + ".sharepoint.com:/sites/" + config.sitename + ":/lists/" + config.listid + "/items",
            spShowListItemsAllFieldsEp: "https://graph.microsoft.com/v1.0/sites/" + config.portalname + ".sharepoint.com:/sites/" + config.sitename + ":/lists/" + config.listid + "/items?expand=fields",
        };
        // this can be used for login or token request, however in more complex situations this can have diverging options
        var requestObj = {
            scopes: ["user.read"]
        };
        var myMSALObj = new Msal.UserAgentApplication(msalConfig);

        // Register Callbacks for redirect flow
        myMSALObj.handleRedirectCallback(authRedirectCallBack);

        function callMSGraph(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 signIn() {
            myMSALObj.loginPopup(requestObj).then(function (loginResponse) {
                //Login Success
                showWelcomeMessage();
                acquireTokenPopupAndCallMSGraph();
            }).catch(function (error) {
                console.log(error);
            });
        }

        function acquireTokenPopupAndCallMSGraph() {
            //Always start with acquireTokenSilent to obtain a token in the signed in user from cache
            myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
                callMSGraph(graphConfig.graphMeEndpoint, 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) {
                        callMSGraph(graphConfig.graphMeEndpoint, 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();');
            var btn1 = document.getElementById('btnAllLists');
            btn1.setAttribute('onclick', "GetWithEndPoint('" + graphConfig.spShowAllListsEp + "');");
            var btn2 = document.getElementById('btnListItems');
            btn2.setAttribute('onclick', "GetWithEndPoint('" + graphConfig.spShowListItemsEp + "');");
            var btn3 = document.getElementById('btnListItemsAllFields');
            btn3.setAttribute('onclick', "GetWithEndPoint('" + graphConfig.spShowListItemsAllFieldsEp + "');");
        }

        //This function can be removed if you do not need to support IE
        function acquireTokenRedirectAndCallMSGraph() {
            //Always start with acquireTokenSilent to obtain a token in the signed in user from cache
            myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
                callMSGraph(graphConfig.graphMeEndpoint, tokenResponse.accessToken, graphAPICallback);
            }).catch(function (error) {
                console.log(error);
                // Upon acquireTokenSilent failure (due to consent or interaction or login required ONLY)
                // Call acquireTokenRedirect
                if (requiresInteraction(error.errorCode)) {
                    myMSALObj.acquireTokenRedirect(requestObj);
                }
            });
        }

        function authRedirectCallBack(error, response) {
            if (error) {
                console.log(error);
            }
            else {
                if (response.tokenType === "access_token") {
                    callMSGraph(graphConfig.graphEndpoint, response.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";
        }
        function signOut() {
            myMSALObj.logout();
        }

        // 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();
                acquireTokenPopupAndCallMSGraph();
            }
        }
        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();
                acquireTokenRedirectAndCallMSGraph();
            }
        } else {
            console.error('Please set a valid login type');
        }
    </script>

    <script>
        function GetWithEndPoint(endpointString) {
            myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
                callMSGraph(endpointString, tokenResponse.accessToken, graphAPICallback);
            }).catch(function (error) {
                console.log(error);
                if (requiresInteraction(error.errorCode)) {
                    myMSALObj.acquireTokenPopup(requestObj).then(function (tokenResponse) {
                        callMSGraph(endpointString, tokenResponse.accessToken, graphAPICallback);
                    }).catch(function (error) {
                        console.log(error);
                    });
                }
            });
        }
    </script>

</body>
</html>

单击任一返回列表项的按钮将引发此消息,我理解这是权限。

    {
      "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.list)('myid')/items",
      "value": []
    }

我的期望是,我将从Graph Explorer获得相同的结果。但这表明我没有权限。我尝试了一些不同的列表,结果始终相同。我可以得到所有清单的清单。但是尝试从列表中获取项目失败。

我们不能在JS中使用Graph API来获取列表项吗?

这是来自Azure的Azure委托权限,我认为这应该是获取列表项所需要的全部。 azure site permissions azure file permissions

1 个答案:

答案 0 :(得分:1)

  

但这表明我没有权限

是的,空白结果通常表示Get Items endpoint缺少以下权限之一(在您的情况下为已委派的权限):

  • Sites.Read.All-阅读所有网站集中的项目
  • Sites.ReadWrite.All-编辑或删除所有网站集中的项目