使用DTO和总线方案进行资源授权

时间:2016-04-14 12:12:02

标签: asp.net-core

在ASP.NET Core上我有以下控制器:

public class MessageApiController : Controller {

  private readonly IMediator _mediator;

  public MessageApiController(IMediator mediator) {
    _mediator = mediator;
  }

  [HttpGet("messages")]
  public async Task<IActionResult> Get(MessageGetQuery query) {
    MessageGetReply reply = await _mediator.SendAsync(query);         
    return Ok(reply);
  }

  [HttpDelete("messages")]
  public async Task<IActionResult> Delete(MessageDeleteModel model) {
    MessageDeleteReply reply = await _mediator.SendAsync(model);         
    return Ok(reply);
  }

}

我有一个带有方法句柄的处理程序类来执行此操作:

GET (简称为简称)

public async MessageGetReply Handle(MessageGetQuery query) {

  IQueryable<Message> messages = _context.Messages.AsQueryable();

  messages = messages.Include(x => x.Author).Include(x => x.Recipients);

  // Omitted: Filter messages according to query

  List<Message> result = await messages.ToListAsync();

  // Omitted: Create MessageGetReply from result

} // Handle

删除(简称为简称)

public async MessageDeleteReply Handle(MessageDeleteModel model) {

  Message message = await _context.Messages.FirstOrDefaultAsync(x => x.Id == model.Id);

  if (message != null) {
    _context.Remove(message);
    await _context.SaveChangesAsync();
  }

  // Omitted: Return reply

} // Handle

授权方案如下:

获取
1.用户必须通过身份验证 2. User.Id必须等于Message.RecipientId;

删除
1.用户必须通过身份验证 2. User.Id必须等于Message.AuthorId;

所以我创建了以下资源授权处理程序:

public class MessageAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Message> {

  protected override void Handle(AuthorizationContext context, OperationAuthorizationRequirement requirement, Message resource) {

    if (requirement == Operations.Delete) {        
      if (resource.AuthorId.ToString() == context.User.FindFirstValue(ClaimTypes.NameIdentifier))
        context.Succeed(requirement);
    }

    if (requirement == Operations.Read) {
      if (resource.RecipientId.ToString() == context.User.FindFirstValue(ClaimTypes.NameIdentifier)))
        context.Succeed(requirement);
    }

  } // Handle

}

出现了一些问题:

  1. 在GET中我应该将所有邮件传递给授权处理程序吗?

    实际上消息是由MessageGetQuery.AuthorId过滤的...... 因此授权处理程序可以接收MessageGetQuery.AuthorId而不是List ... 但感觉很奇怪,因为资源是消息列表。 MessageGetQuery只是一个DTO。

  2. 授权可以与DTO(查询和模型)相关联但是有意义吗?
    当DTO的信息少于实体时,问题就出现了,我需要这些信息来做出授权决定......

  3. 如果将实体用作资源,我将无法进行投影:

    IQueryable<Message> messages = _context.Messages.AsQueryable();
    
    messages = messages.Include(x => x.Author).Include(x => x.Recipients);
    
    // Omitted: Filter messages according to query
    
    List<Message> result = await messages.ToListAsync();
    
    // CALL authorization and send the resource messages ...
    
    // Omitted: Create MessageGetReply from result
    
  4. 一个解决方案是拥有一个用于读取消息的AuthorizationHandler,一个用于删除消息的AuthorizationHandler ...第一个将采用消息列表,第二个消息,...然而,我会参加很多课程。

  5. 在控制器中直接使用实体并且没有DTO时,一切都变得更简单,但恕我直言,不应该这样做...

1 个答案:

答案 0 :(得分:1)

在RC2中,我们删除了auth处理程序中的对象限制,因此您将能够使用,例如,int。因此,您可以将您的仓库注入处理程序并根据需要提取您的DTO。