azure AD认证问题与剃刀处理程序



我在一个已经有标准登录页面的web应用程序中使用msal.js进行用户身份验证时遇到了一个奇怪的问题。我对Azure AD完全陌生,所以我可能错过了一些基本的东西。在同一家公司工作的另一个人向我指出了msal.js,但他使用PHP,而我们的应用程序是一个。NET Core 3应用程序。标准登录工作完美,当提交包含用户名和密码的表单时,触发处理程序后面的代码。这是我为了处理Azure AD身份验证而添加到页面的javascript代码片段:

<script type="text/javascript">
const appCfg =
{
auth:
{
clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',                                       // Carlsberg Prospect.
authority: 'https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/',   // Url autorità con id tenant della directory predefinita.
redirectUri: 'https://localhost:44385/Index'
}
};
var msalObj = new msal.PublicClientApplication(appCfg);
function openLogin()
{
msalObj.loginPopup().then
(function (idToken)
{
$('#LoginModel_rmUsername').val(idToken.account.username);
$('#LoginModel_rmPassword').val(idToken.account.username);
$('#main-login-btn').trigger('click');
}
);
}

对loginPopup的调用打开一个弹出窗口,用户必须在其中插入他的邮件和密码,并且承诺工作良好,为我提供与用户关联的令牌。jquery语句只是模拟用户单击登录按钮,但是处理程序永远不会触发,而是浏览器重定向到一个显示400错误代码的空页面。通过开发工具,网络选项卡显示了从标准登录发出的相同调用,以及在Azure AD身份验证响应后模拟的按钮单击。我使用的是最新的msal.js版本(2.24.0)。我不是web应用程序的。NET Core的超级粉丝,但这个项目是一个不再为我们工作的人的遗产。

编辑最好添加一些代码来解释我的问题。这是Index.cshtml中的代码:
@page
@model IndexModel
@{
Layout = "_LayoutLogin";
}
@{
ViewBag.Title = "Login";
}
@{
string test = (Model.testEnvironment ? " block" : "none");
}
<div style="text-align:center;padding:.125rem;display:@test">
<div style="border-radius:.25rem;color:white;background-color:#18A754;"><strong>** TEST **</strong></div>
</div>
<div class="album py-5 bg-light">
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<center>
<h6><strong>Sia Field</strong> - Application Login</h6>
</center>
<div class="card mb-12 shadow-sm">
<div class="card-body">
<form method="POST" id="login-form" asp-page-handler="LogIn">
<p class="card-text text-center">
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(m => m.LoginModel.Azienda)
<select asp-for="LoginModel.Azienda" class="form-control" asp-items="@Model.ListOfAziende"></select>
@Html.ValidationMessageFor(m => m.LoginModel.Azienda, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.LoginModel.Username)
@Html.TextBoxFor(m => m.LoginModel.Username, new { placeholder = "Username", @class = "form-control" })
@Html.ValidationMessageFor(m => m.LoginModel.Username, "", new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.LoginModel.Password)
@Html.PasswordFor(m => m.LoginModel.Password, new { placeholder = "Password", @class = "form-control" })
@Html.ValidationMessageFor(m => m.LoginModel.Password, "", new { @class = "text-danger" })
</div>
@Html.HiddenFor(m => m.LoginModel.rmUsername)
@Html.HiddenFor(m => m.LoginModel.rmPassword)
<button id="main-login-btn" class="btn btn-primary cbutton" style="width: 100%;">Login</button>
<button type="button" id="login-button" class="btn btn-info" style="width: 100%;margin-top:.75rem;" onclick="openLogin();">Entra con l'account corporate Microsoft</button>
</p>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
const appCfg =
{
auth:
{
clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
authority: 'https://login.microsoftonline.com/common/', // Url autorità con id tenant della directory predefinita.
redirectUri: 'https://localhost:44385/index'
}
};
const req =
{
// prompt: 'login'
};
var msalObj = new msal.PublicClientApplication(appCfg);
function openLogin()
{
msalObj.acquireTokenPopup(req)
.then
(
function (response)
{
$('#LoginModel_Username').val(response.account.username);
$('#LoginModel_Password').val(response.account.username);
$('#main-login-btn').trigger('click');
}
).catch
(
function (error)
{
console.log(error);
}
);
}
</script>

,这是Index.cshtml.cs中的代码摘录:

public async Task<IActionResult> OnPostLogIn()
{
try
{
// Verification.  
if (ModelState.IsValid)
{
DSUtenti dsUsers = new DSUtenti();
// Initialization.  
IQueryable<Utenti> loginInfo = dsUsers.GetMyUtente(Convert.ToInt32(this.LoginModel.Azienda), this.LoginModel.Username, this.LoginModel.Password);
if (loginInfo != null && loginInfo.Count() > 0)
{
// Initialization.  
Utenti logindetails = loginInfo.First();

// Login In.  
await this.SignInUser(logindetails, false);

处理程序OnPostLogIn被正确触发,如果我做一个"正常"登录,提供用户名和密码,点击"登录"按钮,但如果我使用"Entra控制"帐户微软公司"按钮,调用acquireTokenPopup()打开微软登录弹出窗口,当承诺返回正确的令牌与用户所需的信息,在随后的(模拟)按下登录按钮的"OnPostLogin"处理程序永远不会被触发,返回HTTP 400错误。显然,如果此时我在标准字段中提供凭据并再次按下Login按钮,则返回相同的错误,直到刷新页面。对不起,这篇编辑文章太长了。

•我建议您正确使用错误处理在使用重定向方法(loginRedirect, acquireTokenRedirect)的认证流中,注册使用handleRedirectCallback()方法重定向后成功或失败调用的回调。此外,弹出体验(loginPopup, acquireTokenPopup)的方法返回promise例如,您可以使用承诺模式(.then and .catch)来处理它们,如下所示:-

myMSALObj.acquireTokenPopup(request).then(
function (response) {
// success response
}).catch(function (error) {
console.log(error);
});
此外,您可以使用acquireTokenPopupacquireTokenRedirect方法通过调用交互式方法来修复问题,如下所示:-
// Request for Access Token
myMSALObj.acquireTokenSilent(request).then(function (response) {
// call API
}).catch( function (error) {
// call acquireTokenPopup in case of acquireTokenSilent failure
// due to consent or interaction required
if (error.errorCode === "consent_required"
|| error.errorCode === "interaction_required"
|| error.errorCode === "login_required") {
myMSALObj.acquireTokenPopup(request).then(
function (response) {
// call API
}).catch(function (error) {
console.log(error);
});
}
});

有关解决登录弹出式登录问题的更多详细信息,请参阅下面的文档链接:-

https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-error-handling-js

最新更新