【发布时间】:2022-01-27 20:23:30
【问题描述】:
我正在开发一款带有 Flutter(移动客户端)的 Sports 移动应用程序,用于跟踪其用户活动数据。在跟踪一项活动(游泳、跑步、步行……)后,它会调用我(使用 springboot)开发的 REST API,并通过 POST 传递该活动数据。然后,我的用户将能够通过 GET 调用 REST API 查看他跟踪的活动的日志。
由于我知道我自己的追踪开发不如Strava、Garmin、华为等,我想让我的应用用户连接他们的Strava、Garmin等账户以获取他们的活动数据,因此我需要用户授权我的应用使用 OAuth 获取该数据。
在第一种方法中,我已经设法使用授权代码授权开发了所有的 OAuth 流程。授权服务器登录由 Flutter 在用户代理(Chrome 选项卡)中启动,一旦资源所有者完成登录并授权我的 Flutter 应用程序,我的 Flutter 应用程序将获取授权代码和对授权服务器的调用以获取令牌.所以我可以说,我的客户端就是我的 Flutter App。 oauth 流程完成后,我将令牌发送到我的 Rest API,以便将它们存储在数据库中。
我的第一个想法是将这些令牌发送到我的后端应用程序,以便将它们存储在数据库中并开发一个流程来获取这些令牌,咨询资源服务器,将每个资源服务器的 json 响应活动解析为我的其余 API 活动模型的活动并存储在我的数据库中。然后,如果资源所有者调用我的 Rest API 来查询其活动,他将收到所有活动的响应(移动应用跟踪的活动 + Strava、Garmin、资源服务器等存储在我的数据库中)。
当用户按下同步按钮并将这些响应直接映射到我的客户端时,我已经放弃了直接从我的客户端和我的 rest api 调用资源服务器的选项,因为我需要这些资源服务器响应的数据在后端以实现奖牌功能。此外,Strava、Garmin 等都有使用限制,我不想让我的资源所有者能够按他们想要的时间按下按钮。
这是我的第一个想法的流程:
步骤:
-
客户端调用授权服务器启动用户代理以进行 oauth 登录。为了使资源所有者登录并授权。 url 和 params 是硬编码的,在我的客户端中是硬编码的。
-
资源所有者登录并授权客户端。
-
回调与代码一起发送。
-
客户端捕获回调代码并向授权服务器发帖以获取令牌。由于一些授权服务器接受 PKCE,因此我尽可能使用 PKCE,以避免攻击和在我的客户端中硬编码我的客户端密码。其他像 Strava 的不允许 PKCE,所以我必须在我的客户端中硬编码客户端密码才能获取令牌。
-
将令牌返回给我的客户后,我会将它们发送到我的 rest api 并存储在标识令牌资源所有者的数据库中。
调用资源服务器:
-
一个定期进程获取每个资源所有者的令牌,并使用每个资源服务器返回的活动更新我的数据库。
-
资源所有者调用rest api并获取所有活动。
第一个想法的问题在于,一些授权服务器允许实施 PKCE (Fitbit),而其他授权服务器则使用客户端密码来创建令牌 (Strava)。由于我需要客户端密码来获取其中一些授权服务器的令牌,因此我已在客户端中对密码进行硬编码,这并不安全。
我知道将客户端机密插入客户端是危险的,因为黑客可以反编译我的客户端并获取客户端机密。如果授权服务器中不允许 PKCE,我不知道如何在不对客户端密码进行硬编码的情况下获取 Strava 的资源所有者令牌。
由于我不想在我的客户端中硬编码我的客户端机密,因为它不安全并且我想将令牌存储在我的数据库中,所以我不认为我的第一种方法是一个好的选择。此外,我正在向我的 REST API 创建一个 POST 请求,以便将访问令牌和刷新令牌存储在我的数据库中,如果我没记错的话,该过程可以直接从后端完成。
我的情况是,我开发了一个公共客户端(移动应用程序),该客户端对客户端机密进行了硬编码,因为当授权服务器不允许 PKCE 获取令牌时,我不知道如何避免这样做.
所以在考虑了所有这些问题之后,我的第二个想法是利用我的 REST API 并从那里调用授权服务器。所以我的客户是保密的,我会使用服务器端应用程序执行 OAuth 流程。
我的想法是基于这张图片。
为了避免我的移动客户端中的客户端秘密硬编码,以下基于图像的代码流是否可以工作并且可以安全地连接到 Strava、Garmin、Polar....?
Strava 连接示例:
移动客户端
-
移动公共客户端调用我的 Rest API 以获取 Strava 授权服务器登录的 URI,其中包含所需的参数,例如:回调、redirect_uri、client_it 等。
-
移动客户端捕获 Rest API GET 响应 URI。
-
移动客户端启动用户代理(Chrome 自定义选项卡)并监听回调。
用户代理
-
向资源所有者显示 strava 的登录提示。
-
资源所有者插入凭据并推送授权。
-
回调启动
移动客户端
-
当我的客户端检测到回调时,返回客户端并从回调 uri 中提取代码。
-
通过帖子将该代码发送到我的 REST API。 (https://myrestapi 正文中的代码)
REST API 客户端
-
现在,客户端是我的 REST API,因为它将使用移动客户端获取的代码调用授权服务器。客户端将获取该代码,并使用硬编码的客户端密码调用授权服务器。使用这种方法,客户端机密不再存在于移动客户端中,因此它是机密的。
-
授权服务器返回令牌,我将它们存储在数据库中。
过程
- 从我的数据库中获取这些令牌并调用 strava 的资源服务器以获取活动。然后将这些活动解析为我的模型并将它们存储到数据库中。
第二种方法是处理客户机密以避免将其公开的好方法吗?或者我做错了什么?我可以遵循什么样的流程以正确的方式做到这一点?我真的被这个案例困住了,而且由于我是 OAuth 世界的新手,我对我所阅读的所有信息感到不知所措。
【问题讨论】:
-
我认为你可以使用 IDENTITY SERVER 进行身份授权看看identityserver.com/articles/…
-
oauth2中有4个方法。您能否看看标准的“授权码”或“隐式”模式,看看它是否符合您的需求?
-
@ch271828n 我正在使用授权码授权,但我的客户端的一部分在移动应用程序中,而在其余的 api 中。正如我所见,现在不推荐使用隐式代码流。我怀疑我的方法是否安全,因为 Stravas API 只允许使用客户端密码来获取令牌,而我无法在我的移动应用程序中对其进行硬编码。
-
@Tasnuvaoshin 你能解释一下你的答案吗? Identity Server 为我的方法提供了什么?
标签: flutter security oauth-2.0 oauth spring-security-oauth2