SPA 的 MSAL JS 目录选择器(切换目录)组件
MSAL JS Directory Chooser (Switch Directory) Component for SPA
Microsoft 是否有(或是否有人知道的任何自定义 JS 组件)目录选择器来为 AAD 安全 SPA 提供“切换目录”功能(当前使用
MSAL JS https://github.com/AzureAD/microsoft-authentication-library-for-js)?
如果你想通过 msal.js
切换 SPA 中的租户,似乎没有关于它的官方演示。根据我的理解,如果你想这样做,你应该解决两件事:
- 您的应用应该能够获取当前帐户所属的所有租户。
- public 客户端 Azure AD 应用程序应该是 multi-tenant one 以便用户能够无缝登录到不同的租户。
对于第1点,我们可以使用this API获取所有用户租户。此 API 属于 Azure 管理 rest API,因此您的 public 客户端 Azure AD 应用程序应获得以下权限,以便登录的用户可以调用此 API 获取所有租户:
我msal.js为你写了一个简单的演示,我认为可以满足你的要求,只需尝试下面的HTML页面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Azure AD 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"/><br/>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
var clientAppID = "<multi tenant public client Azure ad app id>"
var tenantID = "<tenant ID for default login >"
var demoScops = {
scopes:["https://management.azure.com/user_impersonation"]
}
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();
getAllTenants();
}
function showWelcomeMessage() {
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML = 'welcome! ' + myMSALObj.account.userName + '</br>';
var loginbutton = document.getElementById('SignIn');
loginbutton.innerHTML = 'sign out';
loginbutton.setAttribute('onclick', 'signOut();');
}
function getAllTenants(){
myMSALObj.acquireTokenSilent(demoScops).then(function (tokenResponse) {
var accessToken = tokenResponse.accessToken;
$.ajax({
url: "https://management.azure.com/tenants?api-version=2020-01-01",
type: "GET",
async: false,
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Bearer '+ accessToken);},
success: function(data) {
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML += " your current tenant: "+ myMSALObj.account.idToken.tid +", all your tenants :</br>"
data.value.forEach(item=>{
var tentantItem = "<div id='"+item.tenantId+"' style='border: 2px solid grey; margin:5px; width:500px' onclick='switchTenant(this)' > name :"+item.displayName+ " Tenant ID:"+ item.tenantId +"</div>"
divWelcome.innerHTML += tentantItem;
})
}
});
}).catch(function (error) {
console.log(error);
})
}
function switchTenant(obj){
var msalConfig = {
auth: {
clientId: clientAppID,
authority: "https://login.microsoftonline.com/" + $(obj).attr('id')
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
var myMSALObj = new Msal.UserAgentApplication(msalConfig);
myMSALObj.handleRedirectCallback(authRedirectCallBack);
myMSALObj.loginPopup(demoScops).then(function (loginResponse) {
console.log(loginResponse);
location.reload();
}).catch(function (error) {
console.log(error);
});
}
function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
}
}
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>
结果:
登录后,它会显示我当前的租户 ID 和我所有的租户:
单击租户项目后,会提示登录 window 并在成功登录后重新定位页面:
终于:
Microsoft 是否有(或是否有人知道的任何自定义 JS 组件)目录选择器来为 AAD 安全 SPA 提供“切换目录”功能(当前使用 MSAL JS https://github.com/AzureAD/microsoft-authentication-library-for-js)?
如果你想通过 msal.js
切换 SPA 中的租户,似乎没有关于它的官方演示。根据我的理解,如果你想这样做,你应该解决两件事:
- 您的应用应该能够获取当前帐户所属的所有租户。
- public 客户端 Azure AD 应用程序应该是 multi-tenant one 以便用户能够无缝登录到不同的租户。
对于第1点,我们可以使用this API获取所有用户租户。此 API 属于 Azure 管理 rest API,因此您的 public 客户端 Azure AD 应用程序应获得以下权限,以便登录的用户可以调用此 API 获取所有租户:
我msal.js为你写了一个简单的演示,我认为可以满足你的要求,只需尝试下面的HTML页面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Azure AD 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"/><br/>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
var clientAppID = "<multi tenant public client Azure ad app id>"
var tenantID = "<tenant ID for default login >"
var demoScops = {
scopes:["https://management.azure.com/user_impersonation"]
}
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();
getAllTenants();
}
function showWelcomeMessage() {
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML = 'welcome! ' + myMSALObj.account.userName + '</br>';
var loginbutton = document.getElementById('SignIn');
loginbutton.innerHTML = 'sign out';
loginbutton.setAttribute('onclick', 'signOut();');
}
function getAllTenants(){
myMSALObj.acquireTokenSilent(demoScops).then(function (tokenResponse) {
var accessToken = tokenResponse.accessToken;
$.ajax({
url: "https://management.azure.com/tenants?api-version=2020-01-01",
type: "GET",
async: false,
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Bearer '+ accessToken);},
success: function(data) {
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML += " your current tenant: "+ myMSALObj.account.idToken.tid +", all your tenants :</br>"
data.value.forEach(item=>{
var tentantItem = "<div id='"+item.tenantId+"' style='border: 2px solid grey; margin:5px; width:500px' onclick='switchTenant(this)' > name :"+item.displayName+ " Tenant ID:"+ item.tenantId +"</div>"
divWelcome.innerHTML += tentantItem;
})
}
});
}).catch(function (error) {
console.log(error);
})
}
function switchTenant(obj){
var msalConfig = {
auth: {
clientId: clientAppID,
authority: "https://login.microsoftonline.com/" + $(obj).attr('id')
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
var myMSALObj = new Msal.UserAgentApplication(msalConfig);
myMSALObj.handleRedirectCallback(authRedirectCallBack);
myMSALObj.loginPopup(demoScops).then(function (loginResponse) {
console.log(loginResponse);
location.reload();
}).catch(function (error) {
console.log(error);
});
}
function authRedirectCallBack(error, response) {
if (error) {
console.log(error);
}
}
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>
结果:
登录后,它会显示我当前的租户 ID 和我所有的租户:
单击租户项目后,会提示登录 window 并在成功登录后重新定位页面:
终于: