结合 android 客户端、spring-boot 后端和 Oauth2 社交登录的最佳实践

Best practice for combining android client, spring-boot backend and Oauth2 social login

我正在尝试创建一个项目,将 Android 客户端与后端的 spring-boot 微服务架构相结合。客户端应用程序将通过一系列 Rest API 与后端通信,但这样做时需要 login/authentication。对于 authentication/authorisation,这将通过第 3 次 party/social 登录完成 - 即 google/facebook 等使用 Oauth2.

似乎有很多文档解释了 Oauth2 协议的工作原理,包括资源所有者通过授权服务器授予访问权限、代码和令牌交换、重定向到客户端以及使用提供的令牌。我已按照指南进行操作:

https://developers.google.com/identity/protocols/oauth2/native-app

我用它来指导配置一个带有 sign-in 按钮的基本应用程序,这些按钮可用于检索令牌。我现在的问题是我需要做的是扩展第 3 方 sign-in 以涵盖应用程序与 spring-boot 后端之间的其余 API 通信的身份验证。

有许多指南和教程(例如 https://spring.io/guides/tutorials/spring-boot-oauth2/)解释了如何使用社交登录配置 spring-boot 网络应用程序,但其中 none 似乎与此相关给定客户端的项目是一个执行社交登录的移动应用程序,所以我不是 100% 确定如何继续。

据我所知,这两个身份验证必须分开处理。

我目前的想法是,一旦客户端通过身份验证并收到 Oauth2 令牌,就需要将该令牌作为 post 请求中的表单参数直接发送到后端“登录”微服务 body。然后,“登录”微服务将对其接收到的令牌执行自己的验证,如此处引用:

https://developers.google.com/identity/sign-in/web/backend-auth

如果后端服务器验证了令牌,它将有权访问请求的资源。我的意图是使用 google 资源标识字段作为数据库主键。然后可以将其与我的 server-side 数据库中保存的记录进行比较,以检查它是否对应于有效用户。如果收到的令牌有效并且提取的身份与现有数据库记录的身份相匹配,则登录请求有效。这类似于检查用户名和密码哈希。

正如指南所建议的,为了防止每次调用 API 时都需要重新验证令牌,后端服务器应该创建一个 session 或生成自己的令牌以发送回客户端按照传统的 Web 服务器授权。在这种情况下,它将通过 spring-boot rest 控制器在后端完成,并使用从 android 客户端发送的 volley https 请求。

如果登录无效,则不会返回 token/cookie session id,并且 API 响应将指示“无效令牌”或“未找到现有用户”。

下图总结了上述内容:

这种方法对于 Oauth2 是否明智,或者我是否错过了使用 android + 后端服务进行社交登录的要点?有没有easier/better的实现方法?这感觉像是应该经常遇到的事情,但是大多数文档在描述它应该如何工作时都非常混乱。

更新

好的,上述方法是合理的,目前,我有一个 spring-boot oauth2 应用程序,它结合了社交登录提供程序和 oauth2 授权服务器,它可以:

a) 将 web-clients 重定向到相关的社交登录提供商,将 redirecft_uri 设置为授权服务器以执行 code/token 交换 b) 在使用获得的社交登录详细信息创建数据库条目后,生成自己的 oauth2 令牌以发送回客户端。

这对 Web 客户端非常有用 - 在初始授权之后,所有 API 交互都是使用我的授权服务器的令牌完成的,该令牌独立于提供商生成。

接下来我想为移动客户端使用相同的 framewwork/APIs 等。对于 Web 客户端,我所要做的就是向 UI 添加按钮,通过 REST-API 向适当的提供商(例如 http://mybackend.com/oauth2/login/google)发送请求,其余的由浏览器重定向处理。例如android,我目前的提案是:

  1. 向应用程序添加等效按钮并使用 volley 发送等效请求。
  2. 不遵循重定向,而是传递响应位置 header 值以启动移动浏览器 session,并将重定向 uri 设置为适当的 activity应用
  3. 当我的授权服务器完成令牌生成后,它会重定向到上面指定的 activity,它将读取令牌并在以后通过 volley[=] 发送的任何 REST-API 请求中设置77=]

更新2

根据目前收到的反馈,我实现了对 chrome 自定义选项卡的调用,该选项卡将由我的后端重定向到具有适当设置的社交登录提供程序(如配置 server-side ):

Button gLoginButton = findViewById(R.id.gButton) ;
gLoginButton.setOnClickListener(view -> {
    CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
    CustomTabsIntent customTabsIntent = builder.build();
    customTabsIntent.launchUrl(this, "http://example.com/oauth2/authorize/google?redirect_uri=com.example.custom.scheme.redirect://oauth2/redirect"));
});

然后,我的后端完全处理 auth2 授权流程,就像 web-client 一样,我的 AS 将生成的令牌发送到上面重定向 uri 中的自定义方案。然后我在 AndroidManifest.xml 中声明了一个 activity RedirectUriReceiverActivity 来处理自定义方案:

<activity
    android:name=".RedirectUriReceiverActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="com.example.custom.scheme.redirect"/>
    </intent-filter>
</activity>

activity 可以使用 getIntent().getData()

检索令牌

您 运行 在使用外国访问令牌(例如 Facebook 等发布的令牌)时遇到一个常见问题:

  • 您需要多种身份验证方法
  • 您想控制微服务接收的令牌

但是来自 Facebook 的令牌并非设计用于您自己的 API。

OAuth 旨在让每个软件提供商使用自己的授权。服务器 (AS) - 管理与 Google / Facebook(以及可能的许多其他提供商)的连接 - 然后在每种情况下以相同的方式为 API 发行令牌。这意味着您的应用程序和 API 需要处理的事情要少得多。

避免将社交登录包直接集成到您的 Android 应用中,而是使用标准的 OpenID Connect - 通过 AppAuth Libraries.

我的 blog post 解释了该模式及其好处。有许多免费或低成本的 AS 实现供您使用,这将使您的架构更简单,并以最简单的代码提供未来最好的设计选项。