我正在开发一个基于Clean Architecture模式的Android应用程序,我怀疑如何以一种干净的方式实现用户身份验证。下面的解决方案在清洁架构方面是否干净?
我将创建如下用例(从表示层执行):
LoginUseCase
(用于提供登录名和密码,通过远程服务获取api令牌并保存在本地令牌源中)LogoutUseCase
(从LocalTokenSource
清除令牌)
(LocalTokenSource
接口将存储在域层中,其实现将存储在数据层中-存储库类型)
为了在每次应用程序启动时执行令牌刷新(从用户的Angular 来看,这不是一个用例,对吗?)我会在域层创建SessionManager
组件。SessionManager
将负责刷新令牌并将其保存在LocalTokenSource
中。每次活动启动时,我都会从其演示器执行refreshToken()
,对注入的SessionManager.
执行refreshToken()
。
如果它是干净的,那么如何处理将令牌传递给远程服务以执行其他需要令牌的API方法?假设我有PostsRepository
,它从远程服务获取帖子数据。我是否应该将token从用例传递到repo.getPosts(token)
这样的存储库方法?或者将LocalTokenSource
注入到存储库中,这样它就可以自己读取令牌?第二个选项是否违反了Clean Architecture规则,因为LocalTokenSource
将在2层中使用?
2条答案
按热度按时间rqqzpn5f1#
你必须决定的核心问题是:您是希望将授权(以及令牌的使用)建模为业务逻辑的一个方面,还是希望将其视为“实现细节”。
如果您决定使用第一种方法,那么将SessionManager添加到域层并将令牌传递给存储库将是一种一致的建模方法。
如果您决定使用后者,登录/注销/刷新以及令牌的存在可能最好放在“幕后”,即在框架或网关层中。
这两种方法都将遵循Clean Architecture的规则(只要不违反依赖规则)。
0s7z1bwu2#
让我们参考一下主要的来源,《Clean Architecture:A Craftsman's Guide to Software Structure and Design.
首先,让我们确定干净的架构由哪些层组成。以下是书中的一段话:
架构师可以使用单一职责原则和公共闭合原则来分离那些由于不同原因而改变的东西,并收集那些由于相同原因而改变的东西-给定系统意图的上下文。
由于不同的原因会发生哪些变化?
用户界面更改的原因与业务规则无关。业务规则本身可能与应用程序紧密相关,也可能更通用。数据库、查询语言甚至模式都是技术细节,与业务规则或UI无关。因此,我们发现系统至少分为四个解耦的水平层-独立于应用的业务规则、特定于应用的业务规则、UI和数据库。
在书的后面,Robert Martin详细描述了如何构建这4个相应的层:
1.企业业务规则(实体)
1.应用业务规则(用例)
1.接口适配器
1.框架和驱动程序。
现在让我们确定什么是“用例”。这里是另一个报价:
用例是对自动化系统使用方式的描述。它指定用户要提供的输入、要返回给用户的输出以及生成该输出所涉及的处理步骤。
这些元素将是类、函数或模块,它们在体系结构中具有突出位置,并且它们将具有清晰描述其功能的名称。
从用例中,无法判断应用程序是在Web上、胖客户端上、控制台上交付的,还是一个纯服务。
在*用例交互器 * 和 * 数据库 * 之间是数据库 * 网关 *。这些 * gateway * 是多态接口,包含应用程序可以在数据库上执行的每个创建、读取、更新或删除操作的方法。
如果应用程序需要知道昨天登录的所有用户的姓氏,那么 UserGateway 接口将有一个名为 getLastNamesOfUsersWhoLoggedInAfter 的方法,该方法以Date作为参数并返回姓氏列表。
你对“SessionManager”的描述听起来像是“AuthInterceptor”。根据我的经验,我通常把它作为“数据”组件的一部分放在“框架和驱动程序”层。由于它位于“数据”组件中,因此它与数据库和Web服务处于同一级别(圆圈)。所以理论上直接访问远程或本地数据源(dao和rest客户端)没有什么坏处。
然而,说实话,当我没有解耦层时,有时我会在“AuthInterceptor”中同时使用“网关”和“用例”(数据组件),这可能违反了干净的架构,但我相信没有那么严重,因为我仍然在外圈使用这些接口,而没有违反“边界”规则,即内圈,不应该知道任何关于外圈的事。
由于用例必须有“input to be provided by user,the output to be returned to user”,“refreshToken”函数将不是此操作的一部分,因为它根本不涉及用户,因此它将不是您提到的“LoginUseCase”和“LogoutUseCase”这两个用例中的任何一个。
关于你关于“LocalTokenSource”的问题,你将其描述为“repository”,而Clean Architecture将其正确地称为“Gateway”。网关接口位于“接口适配器”层,它们的实现在框架和驱动程序层,所以很明显,在两层中使用网关接口并不真正符合书中描述的清晰架构,但正如我之前提到的,“框架和驱动程序”层是最外层,所以它允许使用他所知道的任何东西,这是内部的“接口适配器”层。
如果你理解了书中描述的清洁架构的思想,以及我提供的参考资料和经验,你就会明白,如果你只是遵循罗伯特·马丁的清洁架构的基本结构和原则,你不需要违反任何东西。