Asp.net core OpenIdConnect访问\令牌大小和访问声明服务器端

Asp.net core OpenIdConnect访问\令牌大小和访问声明服务器端,asp.net-core,claims-based-identity,openid-connect,asp.net-identity-3,openiddict,Asp.net Core,Claims Based Identity,Openid Connect,Asp.net Identity 3,Openiddict,我试图在这里概括几个概念,但我不希望这个问题过于宽泛-基本上我们试图做的是使用角色声明作为权限来锁定我们的API,但我发现access_令牌变得太大了 我们在服务器端使用OpenIddict和ASP.NET Identity 3。我们已经实现了默认的AspNetRoleClaims表来存储我们对每个角色的声明——使用它们作为权限 我们使用自定义的基于策略的声明授权锁定API端点,如下所示: 我发现的主要问题是,我们包含索赔的访问令牌变得非常大。我们正试图使ClaimType和值在数据库中非常小

我试图在这里概括几个概念,但我不希望这个问题过于宽泛-基本上我们试图做的是使用角色声明作为权限来锁定我们的API,但我发现access_令牌变得太大了

我们在服务器端使用OpenIddict和ASP.NET Identity 3。我们已经实现了默认的AspNetRoleClaims表来存储我们对每个角色的声明——使用它们作为权限

我们使用自定义的基于策略的声明授权锁定API端点,如下所示:

我发现的主要问题是,我们包含索赔的访问令牌变得非常大。我们正试图使ClaimType和值在数据库中非常小,以使索赔足迹更小。我们有一个基本的CRUD类型权限方案,因此对于SPA客户端应用程序中的每个“模块”或屏幕,有4个权限。我们向应用程序中添加的模块越多,访问令牌中的声明就越多,我们的授权承载头也变得非常大。我担心随着应用程序的发展,它的可伸缩性会变得不太好

因此,声明被嵌入到access_令牌中,当我点击我的端点时,该端点会被这样的自定义策略锁定

[Authorize(Policy="MyModuleCanRead")]
[HttpGet]
public IEnumerable<MyViewModel> Get()
[授权(Policy=“MyModuleCanRead”)]
[HttpGet]
公共IEnumerable Get()
然后,我可以在AuthorizationHandler中访问我的ASP.NET标识用户和User.Claimes

如果这是一个明显的问题,请提前道歉-但我想知道-为了让基于自定义策略的授权工作-调用处理程序是否绝对需要声明在id\u令牌或access\u令牌中

如果我从access_令牌中删除声明,则我的AuthorizationHandler代码不会被命中,并且我无法访问使用自定义策略锁定的端点

我想知道是否可以使用自定义声明策略,但在授权处理程序中有检查声明的实际代码,这样声明就不会随每个HTTP请求一起传递,而是从授权cookie或数据库中从服务器端获取

*更新*

Pintpoint使用授权处理程序给出的答案,以及关于如何从cookie中删除其他角色声明的评论,正是我想要的

如果这对其他任何人都有帮助-下面是重写UserClaimsPrincipalFactory并防止将角色声明写入cookie的代码。(我有许多角色声明作为权限,cookie和请求头变得太大)

公共类AppClaimsPrincipalFactory:UserClaimsPrincipalFactory
{
public AppClaimsPrincipalFactory(UserManager、UserManager、RoleManager、RoleManager、IOOptions Accessor):基本(UserManager、RoleManager、Options Accessor)
{
}
公共覆盖异步任务CreateAync(ApplicationUser用户)
{
if(user==null)
{
抛出新ArgumentNullException(nameof(user));
}
var userId=await UserManager.GetUserIdAsync(用户);
var userName=await UserManager.GetUserNameAsync(用户);
var id=新的ClaimsEntity(Options.Cookies.ApplicationOkieAuthenticationScheme,
Options.ClaimsIdentity.UserNameClaimType,
Options.ClaimsIdentity.RoleClaimType);
id.AddClaim(新索赔(Options.ClaimsIdentity.UserIdClaimType,userId));
id.AddClaim(新索赔(Options.ClaimsIdentity.UserNameClaimType,userName));
if(UserManager.SupportsUserSecurityStamp)
{
id.AddClaim(新索赔)(Options.ClaimsIdentity.SecurityStampClaimType,
等待UserManager.GetSecurityStampAsync(用户));
}
//删除了添加角色声明的代码
if(UserManager.SupportsUserClaim)
{
id.AddClaims(wait UserManager.GetClaimsAsync(user));
}
返回新的ClaimsPrincipal(id);
}
}
我想知道是否可以使用自定义声明策略,但在授权处理程序中有检查声明的实际代码,这样声明就不会随每个HTTP请求一起传递,而是从授权cookie或数据库中从服务器端获取

这绝对有可能。以下是您可以做到这一点的方法:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Has-Edit-User-Profiles-Permission", builder =>
            {
                builder.RequirePermission("Edit-User-Profiles");
            });
        });
    }
}

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    public PermissionAuthorizationRequirement(string permission)
    {
        if (string.IsNullOrEmpty(permission))
        {
            throw new ArgumentException("The permission cannot be null or empty.", nameof(permission));
        }

        Permission = permission;
    }

    public string Permission { get; set; }
}

public class PermissionAuthorizationHandler :
    AuthorizationHandler<PermissionAuthorizationRequirement>
{
    private readonly UserManager<ApplicationUser> _userManager;

    public PermissionAuthorizationHandler(UserManager<ApplicationUser> userManager)
    {
        if (userManager == null)
        {
            throw new ArgumentNullException(nameof(userManager));
        }

        _userManager = userManager;
    }

    protected override async Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        PermissionAuthorizationRequirement requirement)
    {
        if (context.User == null)
        {
            return;
        }

        var user = await _userManager.GetUserAsync(context.User);
        if (user == null)
        {
            return;
        }

        // Use whatever API you need to ensure the user has the requested permission.
        if (await _userManager.IsInRoleAsync(user, requirement.Permission))
        {
            context.Succeed(requirement);
        }
    }
}

public static class PermissionAuthorizationExtensions
{
    public static AuthorizationPolicyBuilder RequirePermission(
        this AuthorizationPolicyBuilder builder, string permission)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (string.IsNullOrEmpty(permission))
        {
            throw new ArgumentException("The permission cannot be null or empty.", nameof(permission));
        }

        return builder.AddRequirements(new PermissionAuthorizationRequirement(permission));
    }
}
公共类启动
{
public void配置服务(IServiceCollection服务)
{
services.addScope();
services.AddAuthorization(选项=>
{
options.AddPolicy(“具有编辑用户配置文件的权限”,builder=>
{
建造商的要求(“编辑用户配置文件”);
});
});
}
}
公共类许可授权要求:IAAuthorizationRequirement
{
公共权限授权要求(字符串权限)
{
if(string.IsNullOrEmpty(权限))
{
抛出新ArgumentException(“权限不能为null或空。”,nameof(权限));
}
许可=许可;
}
公共字符串权限{get;set;}
}
公共类PermissionAuthorizationHandler:
授权处理程序
{
私有只读用户管理器_UserManager;
公共许可授权处理程序(UserManager UserManager)
{
if(userManager==null)
{
抛出新ArgumentNullException(nameof(userManager));
}
_userManager=userManager;
}
受保护的覆盖异步任务句柄请求同步(
授权HandlerContext上下文,
许可证(授权要求)
{
if(context.User==null)
{
返回;
}
var user=await\u userManager.GetUserAsync(context.user);
if(user==null)
{
返回;
}
//使用您需要的任何API
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Has-Edit-User-Profiles-Permission", builder =>
            {
                builder.RequirePermission("Edit-User-Profiles");
            });
        });
    }
}

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    public PermissionAuthorizationRequirement(string permission)
    {
        if (string.IsNullOrEmpty(permission))
        {
            throw new ArgumentException("The permission cannot be null or empty.", nameof(permission));
        }

        Permission = permission;
    }

    public string Permission { get; set; }
}

public class PermissionAuthorizationHandler :
    AuthorizationHandler<PermissionAuthorizationRequirement>
{
    private readonly UserManager<ApplicationUser> _userManager;

    public PermissionAuthorizationHandler(UserManager<ApplicationUser> userManager)
    {
        if (userManager == null)
        {
            throw new ArgumentNullException(nameof(userManager));
        }

        _userManager = userManager;
    }

    protected override async Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        PermissionAuthorizationRequirement requirement)
    {
        if (context.User == null)
        {
            return;
        }

        var user = await _userManager.GetUserAsync(context.User);
        if (user == null)
        {
            return;
        }

        // Use whatever API you need to ensure the user has the requested permission.
        if (await _userManager.IsInRoleAsync(user, requirement.Permission))
        {
            context.Succeed(requirement);
        }
    }
}

public static class PermissionAuthorizationExtensions
{
    public static AuthorizationPolicyBuilder RequirePermission(
        this AuthorizationPolicyBuilder builder, string permission)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (string.IsNullOrEmpty(permission))
        {
            throw new ArgumentException("The permission cannot be null or empty.", nameof(permission));
        }

        return builder.AddRequirements(new PermissionAuthorizationRequirement(permission));
    }
}