如何在ControllerBase中统一实现用户授权以避免控制器动作代码重复?
在自定义BaseController中统一实现前置授权逻辑
你可以通过重写ControllerBase的**OnActionExecuting**方法来实现全局前置授权,避免在每个Action中重复编写代码。这个方法会在控制器的Action执行前触发,刚好适合做统一的授权校验。
具体实现步骤
1. 定义带授权逻辑的自定义BaseController
在自定义基类中注入你的dbService,然后重写OnActionExecuting方法,把授权校验逻辑放在这里:
public class CustomBaseController : ControllerBase { private readonly IDbService _dbService; // 通过构造函数注入dbService public CustomBaseController(IDbService dbService) { _dbService = dbService; } public override void OnActionExecuting(ActionExecutingContext context) { // 跳过带有[AllowAnonymous]特性的Action授权校验 var hasAllowAnonymous = context.ActionDescriptor.EndpointMetadata .Any(m => m is AllowAnonymousAttribute); if (hasAllowAnonymous) { base.OnActionExecuting(context); return; } // 执行你的授权逻辑 var userItem = _dbService.GetAuthorizedUser(User); if (userItem == null) { // 授权失败时直接返回Unauthorized结果,终止后续Action执行 context.Result = Unauthorized(ResponseMessage.UnAuthorized); return; } // 如果需要在后续Action中使用授权后的userItem,可以存在HttpContext.Items里 HttpContext.Items["AuthorizedUser"] = userItem; // 继续执行后续流程 base.OnActionExecuting(context); } }
2. 让业务控制器继承自定义基类
后续的业务控制器只需要继承CustomBaseController,自动获得前置授权能力:
public class FooController : CustomBaseController { // 构造函数需要传递dbService给基类 public FooController(IDbService dbService) : base(dbService) { } [HttpGet] public IActionResult GetData() { // 如果需要使用授权后的用户信息,从HttpContext.Items中获取 var authorizedUser = HttpContext.Items["AuthorizedUser"] as UserItem; // 编写你的业务逻辑 return Ok("数据内容"); } // 示例:带有[AllowAnonymous]的Action会跳过授权校验 [HttpGet] [AllowAnonymous] public IActionResult PublicData() { return Ok("公开数据"); } }
可选方案:自定义Action过滤器
如果你不想依赖基类继承,也可以用自定义Action过滤器来实现相同逻辑,灵活性更高:
1. 定义授权过滤器
public class CustomAuthorizationFilter : IActionFilter { private readonly IDbService _dbService; public CustomAuthorizationFilter(IDbService dbService) { _dbService = dbService; } public void OnActionExecuting(ActionExecutingContext context) { // 检查是否允许匿名访问 var hasAllowAnonymous = context.ActionDescriptor.EndpointMetadata .Any(m => m is AllowAnonymousAttribute); if (hasAllowAnonymous) return; var controller = context.Controller as ControllerBase; if (controller == null) return; var userItem = _dbService.GetAuthorizedUser(controller.User); if (userItem == null) { context.Result = controller.Unauthorized(ResponseMessage.UnAuthorized); return; } context.HttpContext.Items["AuthorizedUser"] = userItem; } public void OnActionExecuted(ActionExecutedContext context) { // 这里可以写Action执行后的后置逻辑(可选) } }
2. 注册并使用过滤器
- 全局注册(所有控制器生效):在
Program.cs中添加:
builder.Services.AddScoped<CustomAuthorizationFilter>(); builder.Services.AddControllers(options => { options.Filters.Add<CustomAuthorizationFilter>(); });
- 或只在自定义基类上标记(继承基类的控制器生效):
[ServiceFilter(typeof(CustomAuthorizationFilter))] public class CustomBaseController : ControllerBase { }
内容的提问来源于stack exchange,提问作者A Farmanbar
相关产品推荐
相关产品推荐

