基于 Active Directory 的 ASP.NET Core 6 Web API 中的自定义 IAuthenticationFilter

发布于 2025-01-09 10:46:20 字数 1279 浏览 1 评论 0原文

我需要根据本地 Active Directory 中的一些信息实施自定义授权。经过一些研究后,我认为最好的方法是编写自定义身份验证过滤器并将该信息从 AD 添加到声明列表中。

因此,在 IIS 使用 Windows 身份验证对用户进行身份验证后,我计划阅读一些信息并将其放入声明列表中:

public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
  var claims = new List<Claim>();
  claims.Add(new Claim(ClaimTypes.Name, userPrincipal.Name));
  claims.Add(new Claim(ClaimTypes.Role, "client"));
  claims.Add(new Claim("Accounts", "[List of accounts from AD]"));

  var identity = new ClaimsIdentity(claims);

  var principal = new ClaimsPrincipal(new[] { identity });
  context.Principal = principal;
        
  Thread.CurrentPrincipal = context.Principal;
}

我相信这种方法将允许我从任何控制器访问帐户列表。但是,我无法使用以下方法将我的 IAuthenticationFilter 实现添加到全局过滤器列表中。

builder.Services.AddControllers(config =>
{
    config.Filters.Add(new ApiAuthenticationFilter())
});

这个方法需要IFilterMetaData接口,而我已经实现了IAuthenticationFilter。在以前的 Web API 版本中,我们能够在 Application_Start() 方法中访问 HttpConfiguration,但在 ASP.NET Core 6 Web API 中,我无法找到一种方法将我的过滤器添加到HttpConfiguration

您能否告诉我这是否是正确的方法,或者我应该尝试实现 IActionFilter 接口?或者完全不同的方法。

谢谢!

I need to implement custom authorization based on some information in on-premise Active Directory. After doing some research, I figured that best approach would be to write a custom Authentication Filter and add that information from AD to the list of claims.

So after users are authenticated by IIS using Windows Authentication, I plan to read some information and put that among the list of claims:

public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
  var claims = new List<Claim>();
  claims.Add(new Claim(ClaimTypes.Name, userPrincipal.Name));
  claims.Add(new Claim(ClaimTypes.Role, "client"));
  claims.Add(new Claim("Accounts", "[List of accounts from AD]"));

  var identity = new ClaimsIdentity(claims);

  var principal = new ClaimsPrincipal(new[] { identity });
  context.Principal = principal;
        
  Thread.CurrentPrincipal = context.Principal;
}

I believe that this approach will allow me to access the list of accounts from any controller. However, I am unable to add my IAuthenticationFilter implementation to the list of global filters using the following approach.

builder.Services.AddControllers(config =>
{
    config.Filters.Add(new ApiAuthenticationFilter())
});

This method required IFilterMetaData interface, while I have implemented IAuthenticationFilter. In previous Web API versions, we were able to access HttpConfiguration in Application_Start() method, but in ASP.NET Core 6 Web API, I am unable to find a way to add my filter to HttpConfiguration.

Could you please tell me if that's the right approach, or I should try implementing the IActionFilter interface? Or a different approach altogether.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

╰つ倒转 2025-01-16 10:46:20

我认为 IAuthenticationFilter 不再是向 ClaimsPrincipal 添加声明的正确方法。还有另一个接口 IClaimsTransformation 可以完全满足我的需求。

ASP.NET 网站上发布的示例是为 ClaimsPrincipal 创建一个新的 ClaimsIdentity 实例,而我只需添加到现有声明列表即可实现此目的

public class MyClaimsTransformation : IClaimsTransformation
{
    private readonly IActiveDirectoryService _activeDirectoryService;

    public MyClaimsTransformation(IActiveDirectoryService activeDirectoryService)
    {
        _activeDirectoryService = activeDirectoryService;
    }


    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var identity = principal.Identities.FirstOrDefault(c => c.IsAuthenticated);

        if (identity == null)
        {
            return principal;
        }

        var user = _activeDirectoryService.GetUser(principal.Identity as WindowsIdentity);

        // Add or replace identity.Claims

        if (!principal.HasClaim(c => c.Type == MyClaimTypes.ACCOUNTS))
        {
            identity.AddClaim(new Claim(MyClaimTypes.ACCOUNTS, user.Accounts));

        }

        return principal;
    }
}

:使用 IClaimsTransformation 是为了能够通过 .Net core DI 容器注入依赖项。

在我的 Program.cs 中,我无法使用推荐的身份验证方法使其工作:

builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);

但是,使用 Negotiate 对我有用:

builder. Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();

最后,将我们的自定义 IClaimsTranformation 实现添加到services:

// Claim transformation
builder.Services.AddScoped<IClaimsTransformation, MyClaimsTransformation>();

过去,必须在 ConfigureServices() 方法内完成

有关 IClaimsTransformation 的更多详细信息,请参见此处:
https://learn.microsoft。 com/en-us/aspnet/core/security/authentication/claims?view=aspnetcore-6.0

I figured IAuthenticationFilter is not the right approach anymore to add Claims to the ClaimsPrincipal. There's another interface IClaimsTransformation that does exactly what I wanted.

The example posted on ASP.NET website was creating a new ClaimsIdentity instance to the ClaimsPrincipal while I was able to achieve that by just adding to existing list of claims:

public class MyClaimsTransformation : IClaimsTransformation
{
    private readonly IActiveDirectoryService _activeDirectoryService;

    public MyClaimsTransformation(IActiveDirectoryService activeDirectoryService)
    {
        _activeDirectoryService = activeDirectoryService;
    }


    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var identity = principal.Identities.FirstOrDefault(c => c.IsAuthenticated);

        if (identity == null)
        {
            return principal;
        }

        var user = _activeDirectoryService.GetUser(principal.Identity as WindowsIdentity);

        // Add or replace identity.Claims

        if (!principal.HasClaim(c => c.Type == MyClaimTypes.ACCOUNTS))
        {
            identity.AddClaim(new Claim(MyClaimTypes.ACCOUNTS, user.Accounts));

        }

        return principal;
    }
}

Another advantage of using IClaimsTransformation is to be able to inject dependencies through .Net core DI container.

In my Program.cs, I was unable to make it work using the recommended Authentication method:

builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);

However, using Negotiate worked for me:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();

Finally, add our custom IClaimsTranformation implementation to services:

// Claim transformation
builder.Services.AddScoped<IClaimsTransformation, MyClaimsTransformation>();

In the past, it had to be done inside ConfigureServices() method

More details about IClaimsTransformation are available here:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/claims?view=aspnetcore-6.0

尬尬 2025-01-16 10:46:20

有点晚了,但我已经为您实现了 MinimalApis 和 ControllerBased API 的 IClaimsTransformation 的完整实现
https://github.com/amiru3f/remote-claim-transformation

请注意ClaimsTransofmer 不负责授权/验证。它只负责填写您的索赔,您可以确定用户是否有所需的索赔

A little bit late, but I've implemented a complete implementation of IClaimsTransformation for both MinimalApis and ControllerBased APIs for you
https://github.com/amiru3f/remote-claim-transformation

Please note that ClaimsTransofmer is not responsible for authorization/authentication. It's just responsible to fill up your claims and you can ensure if the User has required claims or not

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文