将授权放在服务层而不是 Web API 层
Posted
技术标签:
【中文标题】将授权放在服务层而不是 Web API 层【英文标题】:Placing authorization into the service layer rather than Web API layer 【发布时间】:2018-03-05 22:46:20 【问题描述】:我正在使用 .NET Core Web API 构建一个 REST API。
我的控制器只是将请求转发到服务层并返回结果
[HttpPost(nameof(Create))]
public async Task<Response<ProviderDTO>> Create([FromBody] ProviderDTO provider)
=> await providerService.CreateAsync(provider);
我现在处于系统中需要开始实施授权的位置。
.NET Core 有 a lot of options 来实现授权,但文档主要在 Web 层的上下文中讨论这些方法(显然是控制器所在的位置)。
我的直觉告诉我,我需要在服务层本身内实现授权,而不是将此授权放在 Web 层。
我的一些推理包括:
-
服务层可能会被控制器以外的东西调用(例如,服务调用其他服务,此时与授权无关)。
可以直接对服务授权进行单元测试,而不必依赖为服务前面的每个“层”编写的集成测试。
保存对数据库的多次调用 -- 如果我需要在授权要求中授权文档,如果它通过了,我必须稍后在服务中提取相同的文档。
问题一
将IPrincipal
和IAuthorizationService
注入我的服务并直接在其中处理授权是一种明智的方法吗?然后 web 层将纯粹检查用户是否登录,也许还有一些更简单的基于策略的属性(例如,这个控制器只允许人员策略)
问题二
有没有人可以将我链接到任何资源(我做过研究,但没有太多关于这方面的内容)
PS:关于拒绝服务层的请求,我有一个异常处理中间件,可以将自定义异常转换为 HTTP 响应。因此,如果发生未经授权的请求,我将抛出一些未经授权的异常,最终导致 HTTP 403。
【问题讨论】:
【参考方案1】:这完全取决于我们所谈论的授权类型以及实现它所涉及的工作量。
一般来说,将您的服务层与 Web 层混合并不是一个好主意,因此请将它们分开。
Web 授权是一回事 - 你在这里说我有一个用户,他是否被允许访问这个端点/页面/任何东西。如果不是,您甚至可以通过根本不调用服务层来节省资源,并且可以在 Web 层中非常早地拒绝请求,并且非常快速地拒绝资源,而不会浪费资源。
接下来,你说的这个服务层是什么?它是真正与数据库对话的那个,还是在你从数据层获得数据后进行一些数据操作的那个?
我的偏好是有一个单独的数据层和授权层。授权层是应用您需要的任何规则然后返回结果的层,这样您就知道是否需要费心去获取任何数据。它不链接到您的 Web 层,不返回 HTTP 代码,一般来说与 UI 方面无关。
这意味着,如果您有多个客户端,例如一个 Web UI 和一个移动 UI,那么两者都将通过这一层,因此这一层级的工作不会重复。
更好的是,您可能想要构建一个负责返回数据的适当 API,然后您所要做的就是从您拥有的任何客户端处理这一件事,然后您就可以在那里处理您的授权。如果您确保可以将授权层与其他任何东西分开调用,而不依赖于其他任何东西,那么您可以从多个地方调用它,并且可以轻松独立地对其进行测试。
这是人们在构建任何东西之前都会考虑的事情,一旦完成其他所有事情,安全性并不是您添加的最后一件事。您在构建产品时要牢记这一点,因为它涉及很多事情,并且会影响您的架构。
所有东西如何组合在一起的图表会有所帮助。
你们有什么样的架构? 您所说的授权涉及程度如何? 我们在谈论什么样的客户?在此之前有很多问题需要回答。
我再提几点,你发表了一些声明:
服务层可以被控制器以外的东西调用 (例如,服务调用其他服务,这不会是 与授权有关)。
服务授权可以直接进行单元测试,而不是 依赖为每个“层”编写的集成测试 在服务前面。
如果您正在考虑微服务,也就是许多独立运行的小服务,那么您绝对需要关注安全性,具体取决于这些东西是如何访问和相互通信的。
这就是你编写授权层的原因,一切都通过它,这是你测试的,而不关心任何 UI 类型的东西。
【讨论】:
以上是关于将授权放在服务层而不是 Web API 层的主要内容,如果未能解决你的问题,请参考以下文章