首页 > 解决方案 > 验证 azure python 函数以从 AJAX 请求调用它而不暴露令牌或密钥

问题描述

我创建了一个并通过托管在 Azure上的代码Python Azure Function调用它。JSApp Service

我需要设置azure active directory authentication这个功能。我已经在 azure function app 和 azure app service 中配置了 azure Active Directory 身份验证,并在两者上都启用了 CORS,但仍然面临 CORS 问题

从源“app-service-url”的“azure-function-url”重定向到“https://login.windows.net”对 XMLHttpRequest 的访问已被 CORS 策略阻止:没有“Access-Control-Allow-Origin”请求的资源上存在标头。

基本上我想要对 azure python 函数进行身份验证,以便我可以从 AJAX 请求调用它而不在应用服务中公开令牌?我做错什么了吗?

还有一种方法可以在使用 azure Active Directory 身份验证的同时使用 azure 函数返回登录用户的电子邮件 ID 吗?我可以在 c# 中找到一个代码示例,如下所示。

laimsPrincipal cp = ClaimsPrincipal.Current;
string welcome = string.Format("Welcome, {0} {1}!", 
cp.FindFirst(ClaimTypes.GivenName).Value, `cp.FindFirst(ClaimTypes.Surname).Value);`

现在的问题是,我需要使用 Python 来执行此操作,但我无法在网上找到示例。谁能指出我正确的方向?或者也许帮助翻译这段代码。

标签: javascriptpythonazureazure-active-directory

解决方案


这是一个从 html/JS 代码调用 Azure 函数的简单演示。

步骤 1:您应该注册一个 Azure AD 应用程序作为您的客户端,以便您可以使用此应用程序登录用户并获取令牌:

在此处输入图像描述

在这种情况下,它需要 Microsoft Graph API 读取用户权限: 在此处输入图像描述

**Step2:**用下面的代码创建一个python函数来测试:

import logging
import base64
import azure.functions as func
import json


def main(req: func.HttpRequest) -> func.HttpResponse:

    accessTokenPayLoad = req.headers.get("Authorization").replace("Bearer ","").split(".")[1]
    data = base64.b64decode(accessTokenPayLoad + '==')
    jsonObj = json.loads(data)
    upn = jsonObj['upn']
    return func.HttpResponse("hello, " + upn)
    
    

基本上,这个函数只是从访问令牌中读取用户的 upn 来读取用户的电子邮件 ID。

Step3创建函数应用程序后,请启用 CORS 以便它可以接受来自静态 HTML 的请求: 在此处输入图像描述

Step4下面的代码是登录用户并获取token调用函数的HTML/JS代码示例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    
    <title>Azure Function test</title>
    <script type="text/javascript" src="https://alcdn.msauth.net/lib/1.4.4/js/msal.min.js"></script>

</head>
<body>
    <div >
                    
        <button id="SignIn" onclick="signIn()">Sign in</button><br/>
        <div id="WelcomeMessage"></div><br/>
        <div id="functionResult"></div>
    </div>
</body>

<script>
    
    var clientAppID = "<your client app id>"
    var tenantID = "<your tenant name/id>"
    var functionURL = "<your function url>";
    
    var demoScops = {
         scopes:["user.read"]
    }

    var msalConfig = {
             auth: {
                 clientId: clientAppID,
                 authority: "https://login.microsoftonline.com/" + tenantID
            },
             cache: {
                 cacheLocation: "localStorage",
                 storeAuthStateInCookie: true
            }
    };
     

    var myMSALObj = new Msal.UserAgentApplication(msalConfig);
    myMSALObj.handleRedirectCallback(authRedirectCallBack);
             
    
    function signIn() {
     
         myMSALObj.loginPopup(demoScops).then(function (loginResponse) {
            console.log(loginResponse);
            initPage();
             
         }).catch(function (error) {
             console.log(error);
         });
     }
     
    function initPage(){
        showWelcomeMessage();
        getGraphAccessTokenToCallFunction()
     }
     
     
     function callFunction(accessToken){

        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function() { 
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
                document.getElementById('functionResult').innerHTML = xmlHttp.responseText;
            }
        }
        xmlHttp.open("GET", functionURL, true);
        xmlHttp.setRequestHeader("Authorization", "Bearer " + accessToken);
        xmlHttp.send(null);
        
     }
     
     
     function getGraphAccessTokenToCallFunction(){
         myMSALObj.acquireTokenSilent(demoScops).then(function (tokenResponse) {
         
              console.log(tokenResponse.accessToken);
              callFunction(tokenResponse.accessToken);
              
         }).catch(function (error) {
              console.log(error);
              })
        }     
     
     function showWelcomeMessage() {
             
         var divWelcome = document.getElementById('WelcomeMessage');
         divWelcome.innerHTML = 'welcome! ' + myMSALObj.account.name ;
         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") {
                 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";
     }
     

     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;

     var loginType = isIE ? "REDIRECT" : "POPUP";
     
     if (loginType === 'POPUP') {
          if (myMSALObj.getAccount()) {
              initPage()
          }
     }
     else if (loginType === 'REDIRECT') {
         document.getElementById("SignIn").onclick = function () {
              myMSALObj.loginRedirect(requestObj);
         };
         if (myMSALObj.getAccount() && !myMSALObj.isCallback(window.location.hash)) {
              initPage()
          }
     } else {
         console.error('Please set a valid login type');
     }
     
     

      function signOut() {
          window.localStorage.clear();
          myMSALObj.logout();
      }
    
</script>

</html>

结果: 在此处输入图像描述


推荐阅读