我意识到这个问题听起来相当长且复杂!我会尽力解释。 我有一个 ASP.NET Core 5 应用程序,它是我的 Angular 应用程序的 BFF(前端的后端)。您必须使用 Azure AD 登录才能访问 SPA。结果保存在 cookie 中,因此我们有 2 个身份验证方案(Azure AD 和 cookie)。无需身份验证即可访问图像等资源。
问题是我有一个 HomeController,它有一个
Index()
操作,它有一个 [AuthorizeForScopes]
和 [Authorize]
属性,用于检查用户是否登录并授权范围。如果没有,AuthorizeForScopes
会将他们带到 Microsoft 登录页面。如果他们已登录,该方法会重定向到运行 SPA 的/home
。
此设置有一些问题:
/
HomeController.Index()
方法在那里运行。return PhysicalFile(..)
之类的东西并不是一个很好的解决方案;在开发过程中,由于 webpack 代理等原因,该路径有所不同...而在生产过程中,由于某种原因,SPA 未正确加载。[Authorize]
和 [AuthorizeForScopes]
标签会立即将用户带到 MS 登录屏幕。我无法真正很好地完成这两件事。下面是一些代码来解释原因:
家庭控制器
[Route("/")]
public class HomeController : Controller
{
[HttpGet]
[Authorize]
[AuthorizeForScopes(ScopeKeySection = "Scopes")]
public IActionResult Index()
{
// We can't run the SPA on "/" because we need to intercept that here to require that the user is authorized before accessing the SPA.
return Redirect("/home");
}
}
重要的中间件
// This is done AFTER useStaticFiles(), useEndpoints() and useSpaStaticFiles()
// Redirect the user to authenticate if the user isnt at this moment
// All static frontend related files are served using the UseSpaStaticFiles middleware
// What's left is the index.html
app.Use(async (context, next) =>
{
if (context.User?.Identity?.IsAuthenticated != true)
{
await context.ChallengeAsync(WellKnownAuthenticationSchemes.OpenIdConnect);
}
else
{
await next();
}
});
授权
// Some other auth config is left out; it's not important.
services.Configure<CookieAuthenticationOptions>("Cookie", opt =>
{
opt.Cookie.IsEssential = true;
opt.Cookie.Name = "auth";
opt.Cookie.SameSite = SameSiteMode.Lax; // Required due to cross origin nature of signin-oidc callback
opt.Cookie.SecurePolicy = Environment.IsDevelopment()
? CookieSecurePolicy.SameAsRequest
: CookieSecurePolicy.Always;
opt.Cookie.HttpOnly = true;
opt.SlidingExpiration = true;
opt.ExpireTimeSpan = TimeSpan.FromDays(90);
});
services.AddAuthentication("Cookie");
services
.AddMicrosoftIdentityWebAppAuthentication(Configuration,
cookieScheme: "Cookie")
.EnableTokenAcquisitionToCallDownstreamApi(Configuration.GetValue<string>("Scopes").Split(" "))
.AddDistributedTokenCaches();
所以,总结一下:
/login
上运行,然后按该页面上的按钮运行当前的 [Authorize]
和 [AuthorizeForScopes]
逻辑于 Index()
/
上运行,并且只有在用户登录并授权范围时才可以访问。我非常感谢您的帮助!
有一个名为 OidcProxy.Net 的框架。通过将其安装在您的 .net 项目中,您可以在 / 上提供 SPA,就像您所描述的那样,并且它负责身份验证。
框架提供了一个端点(/.auth/me),如果未找到经过身份验证的用户,则返回 404;如果用户已通过身份验证,则返回 200 ok 以及用户信息。
要对用户进行身份验证,SPA 可以导航到
/.auth/login
,这将对用户进行身份验证。
在您的情况下,您需要
OidcProxy.Net.EntraId
包来通过 Azure EntraId 对用户进行身份验证。
查看此演示,了解如何与 Auth0 配合使用: https://github.com/oidcproxydotnet/OidcProxy.Net/tree/main/docs/demos/spa-bffs/auth0/src
并阅读此文件以了解如何使用 Azure EntraId 配置它: https://github.com/oidcproxydotnet/OidcProxy.Net/blob/main/integrationtests/Host.TestApps.EntraId/Program.cs
如果您有任何疑问,请通过问题联系。