首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ASP.Net核心2.1注册自定义ClaimsPrincipal

ASP.Net核心2.1注册自定义ClaimsPrincipal
EN

Stack Overflow用户
提问于 2018-08-17 13:23:38
回答 1查看 12.2K关注 0票数 8

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

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

在ASP.Net MVC5中,我使用了自定义RoleProvider,这基本上就是我试图在这里复制的。

CustomClaimsPrincipal.cs

代码语言:javascript
复制
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

代码语言:javascript
复制
        services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddScoped<ClaimsPrincipal,CustomClaimsPrincipal>();

我不确定上面用Startup.cs编写的代码是否是覆盖ClaimsPrincipal的正确方法,因为我是.Net核心框架的新手。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-17 14:03:27

我想我会以不同的方式来解决这个问题:我会修改ClaimsPrincipal并在ClaimsPrincipal实例中添加它们所属的角色,而不是尝试让ClaimsPrincipal实例与数据库对话来确定它们是否属于某个特定的角色。

要做到这一点,我将使用一个不幸的没有很好文档的特性。身份验证管道公开了一个扩展点,一旦完成身份验证,您就可以转换所创建的ClaimsPrincipal实例。这可以通过IClaimsTransformation接口完成。

代码可能类似于:

代码语言:javascript
复制
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方法将在每次发生身份验证过程时运行,因此最有可能在每个请求上运行,这也意味着它将在每次请求时查询数据库以获取登录用户的角色。

与修改ClaimsPrincipal的实现相比,使用此解决方案的优点是ClaimsPrincipal现在是哑巴的,并且不绑定到您的数据库。只有身份验证管道知道它,这使得测试之类的事情变得更容易,例如,您可以使用特定角色新建一个ClaimsPrincipal,以确保它们有或没有访问特定操作的权限,而不需要绑定到数据库。

票数 32
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51888859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档