You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Razor Pages中如何复用不同授权需求的AuthorizationHandler逻辑?

复用ASP.NET授权Handler逻辑的几种方案

针对不同授权需求重复编写Handler逻辑的问题,这里提供几个实用解决方案:

1. 基于通用需求基类的泛型Handler

定义一个所有Location相关授权需求的基类,让Handler处理这个基类类型而非具体需求类,所有继承自基类的需求都会触发同一个Handler。

实现步骤:

  • 定义需求基类及具体需求:
public abstract class LocationBaseRequirement : IAuthorizationRequirement { }

// 查看Location的需求
public class AccessLocationRequirement : LocationBaseRequirement { }

// 编辑Location的需求
public class EditLocationRequirement : LocationBaseRequirement { }
  • 修改IsAdminOrHigherHandler以处理基类需求:
public class IsAdminOrHigherHandler : AuthorizationHandler<LocationBaseRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        LocationBaseRequirement requirement)
    {
        if (context.User.IsInRole(SD.Roles.Admin.ToString()) || 
            context.User.IsInRole(SD.Roles.Master.ToString()))
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

此后无论是AccessLocationRequirement还是EditLocationRequirement,都会触发这个Handler的逻辑,无需重复编写。

2. 提取核心授权逻辑到独立服务

将可复用的授权判断逻辑封装成独立服务,在多个Handler中注入并调用,彻底避免重复编码。

实现步骤:

  • 创建授权辅助服务:
public interface IAuthorizationHelper
{
    bool IsAdminOrHigher(ClaimsPrincipal user);
    Task<bool> IsZoneManagerForLocationAsync(User user, Location location);
}

public class AuthorizationHelper : IAuthorizationHelper
{
    public bool IsAdminOrHigher(ClaimsPrincipal user)
    {
        return user.IsInRole(SD.Roles.Admin.ToString()) || 
               user.IsInRole(SD.Roles.Master.ToString());
    }

    public async Task<bool> IsZoneManagerForLocationAsync(User user, Location location)
    {
        return user.Zones.Any(z => z.Id == location.Zone.Id) && 
               user.IsInRole(SD.Roles.ZoneManager.ToString());
    }
}
  • 注册服务(在Program.cs中):
builder.Services.AddScoped<IAuthorizationHelper>();
  • 修改原有Handler并创建编辑需求Handler:
// 查看需求的Zone判断Handler
public class InLocationsZoneHandler : AuthorizationHandler<AccessLocationRequirement, Location>
{
    private readonly IUserService _userService;

    public InLocationsZoneHandler(IUserService userService)
    {
        _userService = userService;
    }

    protected override async Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        AccessLocationRequirement requirement,
        Location resource)
    {
        var user = await _userService.GetUserFromContextAsync();
        if (user == null)
        {
            context.Fail();
            return;
        }
        if (user.Zones.Any(z => z.Id == resource.Zone.Id))
        {
            context.Succeed(requirement);
        }
    }
}

// 编辑需求的Handler
public class CanEditLocationHandler : AuthorizationHandler<EditLocationRequirement, Location>
{
    private readonly IUserService _userService;
    private readonly IAuthorizationHelper _authHelper;

    public CanEditLocationHandler(IUserService userService, IAuthorizationHelper authHelper)
    {
        _userService = userService;
        _authHelper = authHelper;
    }

    protected override async Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        EditLocationRequirement requirement,
        Location resource)
    {
        // 复用Admin/Master判断逻辑
        if (_authHelper.IsAdminOrHigher(context.User))
        {
            context.Succeed(requirement);
            return;
        }

        var user = await _userService.GetUserFromContextAsync();
        if (user == null)
        {
            context.Fail();
            return;
        }

        // 复用ZoneManager判断逻辑
        if (await _authHelper.IsZoneManagerForLocationAsync(user, resource))
        {
            context.Succeed(requirement);
        }
    }
}

3. 组合现有需求构建新策略

如果编辑操作的授权逻辑是「满足查看需求 或者 额外的ZoneManager条件」,可直接在策略中组合现有逻辑,避免创建新Handler:

options.AddPolicy("CanEditLocation", policy =>
{
    policy.RequireAssertion(context =>
    {
        // 复用Admin/Master判断
        var isAdminOrMaster = context.User.IsInRole(SD.Roles.Admin.ToString()) || 
                              context.User.IsInRole(SD.Roles.Master.ToString());
        if (isAdminOrMaster) return true;

        var location = context.Resource as Location;
        if (location == null) return false;

        // 判断是否为对应Zone的ZoneManager
        var user = ...; // 从上下文获取用户
        return user.Zones.Any(z => z.Id == location.Zone.Id) && 
               user.IsInRole(SD.Roles.ZoneManager.ToString());
    });
});

方案对比

  • 方案1适合同一类资源的不同操作需求复用通用逻辑,实现成本低;
  • 方案2适合将授权逻辑完全解耦,便于维护和单元测试;
  • 方案3适合快速组合现有逻辑,适用于简单场景。

内容的提问来源于stack exchange,提问作者kj49

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:55:29