提问人:user5974635 提问时间:11/17/2023 最后编辑:marc_suser5974635 更新时间:11/17/2023 访问量:55
.NET 8 Web 应用中的身份验证允许 1) 实体框架/标识以及 2) 使用 Microsoft Entra/AAD 和 Google 的 SSO - 不能同时执行 1 和 2
Authentication in .NET 8 web app allowing 1) Entity Framework / Identity as well as 2) SSO using Microsoft Entra/AAD, and Google - can't do both 1 & 2
问:
我有一个 .NET 8 Web 应用程序,我希望允许使用实体框架/标识进行身份验证,以及使用 Microsoft Entra/Azure Active Directory (AAD) 和 Google 的 SSO。
我可以让这三者都工作,但不能同时工作。要么 Identity 有效,要么 Entra 和 Google 无效;或者身份不起作用,而 Entra 和 Google 可以工作。
问题不在于身份验证本身,因为它似乎总是有效,它只是不记得它已登录以进行下一个请求。Cookie 和/或身份验证方案发生了什么?
以下是以下部分:Program.cs
// Identity (Entity Framework)
// This won't work if Google and Azure below are active
builder.Services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>();
// This works but breaks Google and Azure
//builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = false)
// .AddEntityFrameworkStores<ApplicationDbContext>()
// .AddDefaultTokenProviders()
// .AddSignInManager<SignInManager<ApplicationUser>>();
// Authentication (Azure)
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
// Authentication (Google)
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddGoogle(googleOptions =>
{
googleOptions.ClientId = AppConfig.GetValue("Google:ClientId");
googleOptions.ClientSecret = AppConfig.GetValue("Google:ClientSecret");
googleOptions.Events = new Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents
{
OnRedirectToAuthorizationEndpoint = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
}
};
});
以下是处理使用 Entra 或 Google 登录的方法。只需调用 Challenge 方法,对于 Google,在我得到响应后还有一些工作要做。
[HttpGet, HttpPost, ViewPath]
[Route("login/entra")]
public ActionResult LoginEntra()
{
if (CurrentUser != null)
return Redirect("/");
return Challenge(
new AuthenticationProperties { RedirectUri = "/" },
OpenIdConnectDefaults.AuthenticationScheme);
}
[HttpGet, HttpPost, ViewPath]
[Route("login/google")]
public ActionResult LoginGoogle()
{
if (CurrentUser != null)
return Redirect("/");
return Challenge(
new AuthenticationProperties { RedirectUri = "/login/google-response", AllowRefresh = true },
GoogleDefaults.AuthenticationScheme);
}
[HttpGet, HttpPost, ViewPath]
[Route("login/google-response")]
public async Task<IActionResult> LoginGoogleResponse()
{
string authScheme = CookieAuthenticationDefaults.AuthenticationScheme;
var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme);
if (result?.Succeeded == true)
{
var claimsIdentity = new ClaimsIdentity(result.Principal.Claims, authScheme, ClaimTypes.Name, ClaimTypes.Role);
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
var authProperties = new AuthenticationProperties
{
IsPersistent = true
};
await HttpContext.SignInAsync(authScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
// Redirect to the desired page after login
return Redirect("/");
}
else
{
// The user might not be authenticated, handle accordingly
return Challenge(GoogleDefaults.AuthenticationScheme);
}
}
最后,这是当用户使用电子邮件和密码进行身份验证时调用的 API 方法。我自己处理密码加密,所以我还需要验证登录凭据。UserDAO 是我的自定义类,它连接到数据库以执行与用户相关的功能并存储“用户”对象(那里没有疯狂的事情)。
[HttpPost, ApiRequest]
[Route("api/Account/Login")]
public async Task<ActionResult> Login(string email, string password, bool rememberMe = true)
{
try
{
string authScheme = IdentityConstants.ApplicationScheme;
// Retrieve the user by their email
ApplicationUser user = await UserManager.FindByEmailAsync(email);
if (user == null)
throw new UnauthorizedAccessException("Invalid email address or password.");
// Verify the user's password
bool isPasswordValid = UserDAO.VerifyPassword(email, password);
if (!isPasswordValid)
throw new UnauthorizedAccessException("Invalid email address or password.");
UserDAO userObj = new UserDAO(email);
// The password is valid, so sign in the user
// This bypasses the built-in password check and signs in the user directly
await SignInManager.SignInAsync(user, true);
// bool test = SignInManager.IsSignedIn(???);
// Set a cookie to remember the email for the form
if (rememberMe)
Response.Cookies.Append("User.Email", email);
// Determine the redirect URL
string redirect = "/";
// Return success
return JsonWebResult.Success(new { Redirect = redirect });
}
catch (Exception ex)
{
return JsonWebResult.Error(ex.Message);
}
}
我尝试不指定 Entra 和 Google 的身份验证方案。然后 EF / Identity 有效,但 Entra 和 Google 不起作用。
我还尝试使用 AddIdentity 而不是 AddDefaultIdentity。这奏效了,但破坏了 Entra 和 Google。
基本上,我尝试过的所有使 Identity 发挥作用的东西都破坏了 Entra 和 Google。
同样,身份验证本身始终有效 - 它只是不“记住”用户已登录。如果我在 Identity 工作时使用 Entra 登录,它将成功进行身份验证,但在下一个请求中将为 false。如果我更改代码并再次运行它,确保 Entra 正常运行(并破坏 Identity),它实际上显示我已登录到 Entra。CurrentUser.Identity.IsAuthenticated
答: 暂无答案
评论