Authentication与Authorization应归属哪一层?哪种实现方案更优?
首先得把认证和授权的本质区分开,这是判断分层的核心:
1. 认证:属于基础设施/网关层职责,Middleware是合理选择
认证的核心是「验证请求者的身份是否合法」——比如验证JWT Token、Cookie的有效性,确认请求者确实是声称的那个用户。这是所有业务请求的前置通用逻辑,和具体业务规则无关。
框架提供的Middleware(比如ASP.NET Core的JwtBearer中间件、Spring Security的过滤器)就是专门干这个的:它们能统一处理所有入口请求的身份验证,把验证后的用户信息(比如ID、角色)注入到请求上下文里,供后续业务层使用。这种实现方式既复用了成熟的框架能力,又能让领域层彻底摆脱“身份验证”这种非业务逻辑,符合DDD的分层原则。
2. 授权:分两种场景,不能一概而论
授权的核心是「判断已认证用户是否有资格执行某个操作」,这里要拆成两种完全不同的场景:
通用粗粒度授权:适合放在Middleware/Controller层
比如「只有管理员角色能访问后台接口」、「所有登录用户都能查看公开资料」——这类授权是基于角色、权限组的粗粒度控制,和具体业务上下文无关。用框架提供的注解(比如.NET的[Authorize(Roles="Admin")]、Spring的@PreAuthorize("hasRole('ADMIN')"))或者Middleware处理是最高效的:
- 代码简洁,不用在每个业务方法里重复判断;
- 能提前拦截无权限请求,减少业务层的无效处理。
业务专属细粒度授权:必须放在Service/UseCase/领域层
这才是DDD中真正的业务逻辑,比如:
- 「只有订单的创建者才能修改该订单」;
- 「用户只能查看自己名下的银行账户余额」;
- 「VIP用户才能享受折扣价购买商品」。
这类授权和业务规则强绑定,依赖具体的业务上下文(比如订单的创建人ID、用户的账户归属、用户的会员等级),必须放在业务层实现:
- 如果把这种逻辑放到Middleware/Controller,你会发现需要在外部层查询大量业务数据(比如查订单创建人),导致外层和领域模型耦合;
- 领域层需要保证业务规则的一致性,把授权逻辑封装在Service或领域实体里(比如
Order类提供CanModify(User currentUser)方法),能确保无论通过什么入口(API、后台任务、CLI)调用,都遵循同样的授权规则。
为什么很多开发者会把授权放到外层?
- 框架工具太易用:很多人会直接用框架提供的注解搞定所有授权,忽略了业务专属授权的特殊性;
- 对DDD分层边界理解模糊:没分清「通用技术逻辑」和「业务规则逻辑」的区别;
- 小项目场景下的妥协:小项目业务逻辑简单,混在一起也能跑,但随着业务复杂度提升,会出现授权规则散落在各处、难以维护的问题。
最优实践总结
- 认证:统一用框架Middleware处理,专注于身份合法性验证,把用户身份信息传递到上下文;
- 通用授权:用Middleware/Controller层的注解/过滤器处理粗粒度的角色、权限组控制;
- 业务授权:在Service/UseCase或领域层实现,和业务逻辑绑定,保证规则一致性。
举个.NET的简单例子:
// 1. 认证:Startup里配置JwtBearer中间件,验证Token并注入HttpContext.User services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { /* 配置Token验证规则 */ }); // 2. 通用授权:Controller层用注解拦截管理员接口 [Authorize(Roles = "OrderManager")] public class OrderController : ControllerBase { private readonly IOrderService _orderService; public OrderController(IOrderService orderService) => _orderService = orderService; [HttpPut("{id}")] public async Task<IActionResult> UpdateOrder(Guid id, UpdateOrderDto dto) { var currentUserId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; await _orderService.UpdateOrder(id, dto, currentUserId); return Ok(); } } // 3. 业务授权:Service层处理订单专属的授权逻辑 public class OrderService : IOrderService { private readonly IOrderRepository _orderRepo; public OrderService(IOrderRepository orderRepo) => _orderRepo = orderRepo; public async Task UpdateOrder(Guid orderId, UpdateOrderDto dto, string currentUserId) { var order = await _orderRepo.GetById(orderId); // 业务授权判断:只有创建者才能修改 if (order.CreatorId != currentUserId) { throw new UnauthorizedAccessException("无权限修改该订单"); } // 执行订单修改的业务逻辑 order.UpdateDetails(dto); await _orderRepo.SaveChanges(); } }
内容的提问来源于stack exchange,提问作者vupham
相关产品推荐
相关产品推荐

