ASP.Net Core 2.1注册自定义ClaimsPrincipal [英] ASP.Net Core 2.1 register custom ClaimsPrincipal

查看:224
本文介绍了ASP.Net Core 2.1注册自定义ClaimsPrincipal的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建Windows身份验证应用程序,但是角色位于自定义数据库中,而不位于AD上,因此我创建了一个自定义ClaimsPrincipal来覆盖通常在AD中查找角色的User.IsInRole()函数.

I am creating a Windows Authentication app but the roles sit within the custom database and not on the AD so I created a custom ClaimsPrincipal to override the User.IsInRole() function that usually looks at the AD for roles.

但是,在运行应用程序时,它似乎仍在使用原始代码,而不是我的CustomClaimsPrincipal. 我收到错误消息主域和可信域之间的信任关系失败".

However, when running the application it still seems to be using the original code and not my CustomClaimsPrincipal. I get the error "The trust relationship between the primary domain and the trusted domain failed".

在ASP.Net MVC 5中,我使用了一个Custom RoleProvider,这实际上是我要在此处复制的内容.

In ASP.Net MVC 5 I used a Custom RoleProvider which is essentially what I am trying to replicate here.

CustomClaimsPrincipal.cs

public class CustomClaimsPrincipal : ClaimsPrincipal
{
    private readonly ApplicationDbContext _context;

    public CustomClaimsPrincipal(ApplicationDbContext context)
    {
        _context = context;
    }

    public override bool IsInRole(string role)
    {
        var currentUser = ClaimsPrincipal.Current.Identity.Name;

        IdentityUser user = _context.Users.FirstOrDefault(u => u.UserName.Equals(currentUser, StringComparison.CurrentCultureIgnoreCase));

        var roles = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
                    from r in _context.Roles
                    where ur.RoleId == r.Id
                    select r.Name;
        if (user != null)
            return roles.Any(r => r.Equals(role, StringComparison.CurrentCultureIgnoreCase));
        else
            return false;
    }
}

Startup.cs

        services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddScoped<ClaimsPrincipal,CustomClaimsPrincipal>();

由于我是.Net Core框架的新手,因此不确定Startup.cs中的上述代码是否是重写ClaimsPrincipal的正确方法.

Not sure if the above code in Startup.cs is the correct way to override the ClaimsPrincipal as I'm new to the .Net Core framework.

推荐答案

我想我将以不同的方式解决该问题:与其尝试让ClaimsPrincipal实例与数据库进行对话以弄清它们是否属于特定对象,角色,我将修改ClaimsPrincipal并在ClaimsPrincipal实例中添加它们所属的角色.

I think I would tackle that problem differently: instead of trying to have the instance of ClaimsPrincipal talk to the database to figure out if they belong to a specific role, I would modify the ClaimsPrincipal and add the roles they belong to in the ClaimsPrincipal instance.

为此,不幸的是,我将使用一项功能未得到充分证明的功能.身份验证管道公开了一个可扩展点,在该点上,一旦完成身份验证,您就可以转换创建的ClaimsPrincipal实例.可以通过 IClaimsTransformation 界面.

To do so, I would use a feature that is unfortunately not well documented. The authentication pipeline exposes an extensibility point where once the authentication is done, you can transform the ClaimsPrincipal instance that was created. This can be done through the IClaimsTransformation interface.

代码可能类似于:

public class Startup
{
    public void ConfigureServices(ServiceCollection services)
    {
        // Here you'd have your registrations

        services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
    }
}

public class ClaimsTransformer : IClaimsTransformation
{
    private readonly ApplicationDbContext _context;

    public ClaimsTransformer(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var existingClaimsIdentity = (ClaimsIdentity)principal.Identity;
        var currentUserName = existingClaimsIdentity.Name;

        // Initialize a new list of claims for the new identity
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, currentUserName),
            // Potentially add more from the existing claims here
        };

        // Find the user in the DB
        // Add as many role claims as they have roles in the DB
        IdentityUser user = await _context.Users.FirstOrDefaultAsync(u => u.UserName.Equals(currentUserName, StringComparison.CurrentCultureIgnoreCase));
        if (user != null)
        {
            var rolesNames = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
                        from r in _context.Roles
                        where ur.RoleId == r.Id
                        select r.Name;

            claims.AddRange(rolesNames.Select(x => new Claim(ClaimTypes.Role, x)));
        }

        // Build and return the new principal
        var newClaimsIdentity = new ClaimsIdentity(claims, existingClaimsIdentity.AuthenticationType);
        return new ClaimsPrincipal(newClaimsIdentity);
    }
}

要进行全面披露,TransformAsync方法将在每次身份验证过程发生时运行,因此很可能会在每个请求上运行,这也意味着它将在每个请求上查询数据库以获取已登录用户的角色.

For full disclosure, the TransformAsync method will run every time the authentication process takes place, so most likely on every request, also meaning it will query the database on every request to fetch the roles of the logged-in user.

与修改ClaimsPrincipal的实现相比,使用此解决方案的优势在于,ClaimsPrincipal现在为 dumb ,并且不再与您的数据库绑定.只有身份验证管道知道这一点,这使您可以更轻松地进行诸如测试之类的事情,例如,为具有特定角色的ClaimsPrincipal新建一个,以确保他们可以访问或不可以访问特定的操作,而不受其束缚.数据库.

The advantage of using this solution over modifying the implementation of ClaimsPrincipal is that the ClaimsPrincipal is now dumb and not tied to your database. Only the authentication pipeline knows about it, which makes things like testing easier as you could, for example, new-up a ClaimsPrincipal with specific roles to make sure they do or don't have access to specific actions, without being tied to the database.

这篇关于ASP.Net Core 2.1注册自定义ClaimsPrincipal的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆