C# Asp Net Core 3.1自定义角色授权

C# Asp Net Core 3.1自定义角色授权,c#,asp.net-core-3.1,C#,Asp.net Core 3.1,我在上看到了与NetCore2.2基本相同的问题。 当我尝试为我的NetCore3.1应用程序实现时,我遇到了一个错误 System.InvalidCastException: Unable to cast object of type 'System.Security.Claims.ClaimsIdentity' to type 'System.Security.Principal.WindowsIdentity' RoleAuthHandler.cs尝试将标识强制转换为WindowsIde

我在上看到了与NetCore2.2基本相同的问题。 当我尝试为我的NetCore3.1应用程序实现时,我遇到了一个错误

System.InvalidCastException: Unable to cast object of type 'System.Security.Claims.ClaimsIdentity' to type 'System.Security.Principal.WindowsIdentity'
RoleAuthHandler.cs尝试将标识强制转换为WindowsIdentity时出错

我想知道核心2.2和3.1之间是否有变化可以解释这一点,或者我做错了什么。任何帮助都会很好

Startup.cs包含

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddSingleton<IAuthorizationHandler, RoleAuthHandler>();

    services.AddAuthorization(options =>
        options.AddPolicy(
            Role.Admin,
            policy => policy.AddRequirements(new RoleRequirement(Role.Admin))));
}
protected override Task HandleRequirementAsync(
    AuthorizationHandlerContext context,
    RoleRequirement requirement)
{
    var wi = (WindowsIdentity)context.User.Identity;
    var groupSet = new HashSet<string>();

    if (wi.Groups != null)
    {
        foreach (var group in wi.Groups)
        {
            groupSet.Add(group.Translate(typeof(NTAccount)).ToString());
        }
    }

    string[] userRoles = roleService.GetRolesForGroup(groupSet);
    var intersectRoles = Enumerable.Intersect(userRoles, requirement.Roles, StringComparer.OrdinalIgnoreCase);

    if (intersectRoles.Count() > 0)
    {
        context.Succeed(requirement);
    }

    return Task.CompletedTask;
}
RoleRequirement.cs

public class RoleRequirement : IAuthorizationRequirement
{
    public string[] Roles { get; }

    public RoleRequirement(params string[] roles)
    {
        this.Roles = roles;
    }
}
RoleAuthHandler.cs包含

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddSingleton<IAuthorizationHandler, RoleAuthHandler>();

    services.AddAuthorization(options =>
        options.AddPolicy(
            Role.Admin,
            policy => policy.AddRequirements(new RoleRequirement(Role.Admin))));
}
protected override Task HandleRequirementAsync(
    AuthorizationHandlerContext context,
    RoleRequirement requirement)
{
    var wi = (WindowsIdentity)context.User.Identity;
    var groupSet = new HashSet<string>();

    if (wi.Groups != null)
    {
        foreach (var group in wi.Groups)
        {
            groupSet.Add(group.Translate(typeof(NTAccount)).ToString());
        }
    }

    string[] userRoles = roleService.GetRolesForGroup(groupSet);
    var intersectRoles = Enumerable.Intersect(userRoles, requirement.Roles, StringComparer.OrdinalIgnoreCase);

    if (intersectRoles.Count() > 0)
    {
        context.Succeed(requirement);
    }

    return Task.CompletedTask;
}

@谢谢你的提醒。我在某个地方的帖子上看到了这个解决方案,并将其驳回,因为我要查找的信息是“用户属于哪个组”。我没有意识到的是,该信息在索赔实体中是可用的。你的提及让我三思而后行,我找到了答案:

protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        RoleRequirement requirement)
    {
        var claimsIdentity = (ClaimsIdentity)context?.User.Identity;
        var userGroups = claimsIdentity.Claims
            .Where(x => x.Type.Contains("groupsid", StringComparison.OrdinalIgnoreCase))
            .ToList();

        if (userGroups == null || !userGroups.Any())
        {
            return Task.CompletedTask;
        }

        var groupNames = new HashSet<string>();
        foreach (var group in userGroups)
        {
            var groupName = new SecurityIdentifier(group.Value)
                .Translate(typeof(NTAccount))
                .ToString();
            groupNames.Add(groupName);
        }

        var userRoles = this.authenticationService.GetRoles(groupNames.ToArray());

        // If the user is an Admin, always allow
        if (userRoles.Contains(Role.Admin))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        var intersectingRoles = Enumerable.Intersect(
            userRoles,
            requirement?.Roles,
            StringComparer.OrdinalIgnoreCase);
        if (intersectingRoles?.Count() > 0)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
受保护的覆盖任务句柄请求同步(
授权HandlerContext上下文,
角色(要求)
{
var claimsIdentity=(claimsIdentity)context?.User.Identity;
var userGroups=claimsIdentity.Claims
.Where(x=>x.Type.Contains(“groupsid”,StringComparison.OrdinalIgnoreCase))
.ToList();
if(userGroups==null | |!userGroups.Any())
{
返回Task.CompletedTask;
}
var groupNames=newhashset();
foreach(userGroups中的var组)
{
var groupName=新的SecurityIdentifier(group.Value)
.翻译(类型(NTAccount))
.ToString();
groupName.Add(groupName);
}
var userRoles=this.authenticationService.GetRoles(groupNames.ToArray());
//如果用户是管理员,则始终允许
if(userRoles.Contains(Role.Admin))
{
成功(要求);
返回Task.CompletedTask;
}
var intersectingRoles=Enumerable.Intersect(
用户角色,
要求?角色,
普通木糖酶);
if(intersectingRoles?.Count()>0)
{
成功(要求);
}
返回Task.CompletedTask;
}

你能检查一下这行代码var
wi=(WindowsIdentity)context.User.Identity
你应该在你的cas中返回
ClaimsIdentity
你需要更改为
wi=(ClaimsIdentity)context.User.Identity
。我在从2.2迁移到3.1时遇到同样的问题,但是我看到的
ClaimsIdentity
有一个空的
Claims
集合,没有
Name
,那么我如何获得Windows用户信息呢?@lesscode我和你有同样的问题。我在IIS上运行asp.net核心web应用程序,web应用程序被配置为接受匿名身份验证。禁用此选项,只保留Windows身份验证可用,确保声明是Windows标识的声明之一。@MortenNørgaard不幸的是,我们的控制器混合了已验证和匿名端点,因此我们需要在IIS中启用这两种方案。我仍然认为这是一个突破性的变化,但我们能够通过在自定义处理程序的顶部添加代码来解决这个问题,该处理程序会使经过身份验证的请求提前失败(导致对客户端的质询)。详情如下: