javascript - 验证 azure python 函数以从 AJAX 请求调用它而不暴露令牌或密钥
问题描述
我创建了一个并通过托管在 Azure上的代码Python Azure Function
调用它。JS
App 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 来执行此操作,但我无法在网上找到示例。谁能指出我正确的方向?或者也许帮助翻译这段代码。
解决方案
这是一个从 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>
推荐阅读
- asp.net-core - 如何在 MVC 核心 2.0 中使用 DisplayTemplates
- python - python:如何拆分按第一列分组的excel文件
- xpath - xpath 查询到页面上的特定数字
- android - 如何将亚马逊波利文本中的简历添加到 android 中的语音中?
- jquery - jQuery函数不在页面加载时调用
- javascript - 如何在js中连接对象属性
- firebase - 如何处理 Firebase 登录作为首次访问
- java - Appium 收集任何屏幕上的所有文本
- postgresql - 如何检查是否正在复制 Postgres 10 集群?
- reactjs - 无法读取对象的属性