c# - 使用 Azure AD 进行身份验证时,.NET Core 不会在中间件中显示用户声明
问题描述
我有一个多租户 .NET Core Web 应用程序,当前用户的租户通过中间件解析。特别是,租户通过一个名为SaasKit.Multitenancy的库来解决。
要使用这个库,你把这一行放在ConfigureServices()
:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// (omitted for brevity)
// The 'Tenant' type is what you resolve to, using 'ApplicationTenantResolver'
services.AddMultitenancy<Tenant, ApplicationTenantResolver>();
// ...
}
然后你把这条线Configure()
添加到中间件管道中:
public void Configure(IApplicationBuilder app)
{
// ...
app.UseAuthentication();
app.UseMultitenancy<Tenant>(); //this line
app.UseMvc(ConfigureRoutes);
// ...
}
这会导致中间件中的以下方法被执行,该方法解析当前用户的租户:
public async Task<TenantContext<Tenant>> ResolveAsync(HttpContext context)
{
//whatever you need to do to figure out the tenant goes here.
}
这允许将此方法的结果(无论哪个租户解析)注入到您想要的任何类中,如下所示:
private readonly Tenant _tenant;
public HomeController(Tenant tenant)
{
_tenant = tenant;
}
到目前为止,我们一直在使用 .NET Identity 平台对用户进行身份验证,将用户数据存储在我们应用程序的数据库中。但是,我们的一个新租户希望能够通过 SSO 对其用户进行身份验证。
我已经弄清楚了 SSO 的大部分内容——我正在使用 Azure AD 登录用户,并且我组织的 Azure AD 租户将能够与他们的 Identity Provider 联合。简而言之,此代码ConfigureServices
添加了 Identity 和 AzureAD 身份验证:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// rest of the code is omitted for brevity
services.AddIdentity<ApplicationUser, ApplicationRole>(config =>
{
config.User.RequireUniqueEmail = true;
config.Password.RequiredLength = 12;
}).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => _configuration.Bind("AzureAd", options)).AddCookie();
// policy gets user past [Authorize] if they are signed in with Identity OR Azure AD
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder(
AzureADDefaults.AuthenticationScheme,
IdentityConstants.ApplicationScheme
).RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
}
使用 Identity 时,我已经能够使用 UserManager 解析用户的租户,如下所示:
public async Task<TenantContext<Tenant>> ResolveAsync(HttpContext context)
{
TenantContext<Tenant> tenantContext = new TenantContext<Tenant>(new ApplicationTenant());
if (context.User.Identity.IsAuthenticated)
{
var user = await _userManager.Users
.Include(x => x.Tenant)
.FirstOrDefaultAsync(x => x.UserName == email);
if (user?.Tenant != null)
{
tenantContext = new TenantContext<Tenant>(user.Tenant);
_logger.LogDebug("The current tenant is " + user.Tenant.Name);
return await Task.FromResult(tenantContext);
}
}
return await Task.FromResult(tenantContext);
}
我的计划是修改此代码,以获取当前用户的声明,该声明可用于推断用户属于哪个租户。但是,当通过 Azure AD 对用户进行身份验证时HttpContext.User
,尽管用户已登录,但中间件中始终为空。它不是 null,而是HttpContext.User.Identity.IsAuthenticated
始终为 false 且HttpContext.User.Claims
为空。HttpContext.User
一旦路由完成并且代码到达控制器,我只会看到填充的值。
我尝试以几乎所有可行的方式重新组织中间件,但无济于事。令我困惑的是,HttpContext.User
当用户使用 Identity 进行身份验证时,它会填充到租户解析器中。考虑到这一点,我不确定在通过 Azure AD 进行身份验证时如何访问中间件中的用户声明。
我能想到的最佳解决方案是通过调用通过声明解析租户的方法来修改当前租户注入代码的每个实例。如果租户在受 [Authorize] 属性限制的区域中为 null,则意味着用户已通过 Azure AD 登录,这将允许我查看他们的声明。但是,我无法在中间件中访问用户的声明真的让我很困扰,因为我不确定这里到底发生了什么。
解决方案
由于您尝试从自定义组件访问 HttpContext ,因此您将要添加HttpContextAccessor
到您的服务集合中,如下所示:
services.AddHttpContextAccessor();
您现在可以HttpContext
根据需要使用依赖注入进行解析。这可能有帮助,也可能没有帮助,具体取决于您对所使用的中间件的控制程度。
对于它的价值,我在没有额外第三方中间件的情况下仅使用 MSAL 对 AAD 进行身份验证几乎没有问题。祝你好运!
推荐阅读
- python - 如何从 scipy.spatial.Voronoi 获取边界会合点的坐标
- python - 将值插入到文本小部件中,删除以前的值 - Tkinter
- operating-system - 设备队列和等待队列有什么区别?
- javascript - 在 TestCafe 中使用 Selectors,需要抓取带有 id 和 class 的元素
- php - 在第 1 段纯 PHP 之后添加 AdSense 代码
- sequelize.js - Sequelize 在尝试插入外键时给出 500 错误
- java - Java 将 Array 集合排序为 String
- java - 在封闭函数中处理未处理的检查异常
- javascript - 非常奇怪的 jquery/asp.net webforms textarea 最大长度
- javascript - 如何在 django 博客中添加社交分享按钮