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

Authentication与Authorization应归属哪一层?哪种实现方案更优?

认证(Authentication)与授权(Authorization)在DDD架构中的分层实现选择

首先得把认证和授权的本质区分开,这是判断分层的核心:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:45:05