首页 > 解决方案 > 使用第三方身份验证保护资源服务器 RESTful API

问题描述

首先,我有一个使用 Spring Boot 开发的 oauth2 授权服务器,使用 @EnableAuthorizationServer 注释并扩展了 AuthorizationServerConfigurerAdapter。同样的方式,有一个资源服务器用 @EnableResourceServer 注释扩展 ResourceServerConfigurerAdapter。

场景:使用 Google 登录的 Android 应用程序必须以安全的方式调用作为资源服务器的后端 REST API。Android 应用程序必须调用 REST API 以获取记录的用户信息,以使用我的授权服务器生成的提供的访问令牌填充应用程序界面。尝试将应用程序与资源和授权服务器以及 Google 登录集成,我发现以下 Google 开发人员页面:https ://developers.google.com/identity/sign-in/web/backend-auth

他们在那里说:

如果您将 Google 登录与与后端服务器通信的应用或网站一起使用,您可能需要识别服务器上当前登录的用户。要安全地执行此操作,请在用户成功登录后,使用 HTTPS 将用户的 ID 令牌发送到您的服务器。然后,在服务器上,验证 ID 令牌的完整性,并使用令牌中包含的用户信息来建立会话或创建新帐户。

好的,我可以添加一个端点来接收 ID 令牌,没问题。

其他会话,在同一页面的末尾还说:

验证令牌后,检查用户是否已在您的用户数据库中。如果是这样,为用户建立一个经过身份验证的会话。如果用户尚未在您的用户数据库中,请根据 ID 令牌负载中的信息创建新的用户记录,并为用户建立会话。当您在应用程序中检测到新创建的用户时,您可以提示用户提供您需要的任何其他个人资料信息。

这里我们有重点。在验证 Android 应用程序在用户登录 Google 期间发送的 ID 令牌后,如何将应用程序与 API 集成并在我的 Spring 授权服务器上生成访问和刷新令牌以将它们发送到移动应用程序?

标签: springspring-bootspring-securityspring-security-oauth2google-oauth

解决方案


找到的解决方案:我创建了一个自定义授权类型。这样,我可以覆盖身份验证以使用提供者(在本例中为 Google)检查 ID 令牌,如果没问题,让正常流程完成其工作。

基于我的实现:

1)授权服务器:https ://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/custom-grant/src/main/java/demo/Application.java

2)自定义令牌授予者:https ://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/custom-grant/src/main/java/demo/CustomTokenGranter.java :

这是我在 Kotlin 中的自定义实现:

1 )覆盖configure(endpoints: AuthorizationServerEndpointsConfigurer)AuthorizationServerConfigurerAdapter

override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
    endpoints
        .tokenStore(tokenStore)
        .reuseRefreshTokens(false)
        .accessTokenConverter(accessTokenConverter)
        .authenticationManager(authenticationManager)
        .userDetailsService(authUserDetails)
        .tokenGranter(tokenGranter(endpoints))
}

private fun tokenGranter(endpoints: AuthorizationServerEndpointsConfigurer) =
    CompositeTokenGranter(mutableListOf(endpoints.tokenGranter).apply {
        add(GoogleTokenGranter(
                tokenServices = endpoints.tokenServices,
                clientDetailsService = endpoints.clientDetailsService,
                requestFactory = endpoints.oAuth2RequestFactory,
                grantType = GoogleTokenGranter.GRANT_TYPE
            )
        )
    })

2)自定义令牌授予者实现:

class GoogleTokenGranter internal constructor(
    tokenServices: AuthorizationServerTokenServices,
    clientDetailsService: ClientDetailsService,
    requestFactory: OAuth2RequestFactory,
    grantType: String
) : AbstractTokenGranter(tokenServices, clientDetailsService, requestFactory, grantType) {

    override fun getOAuth2Authentication(client: ClientDetails, tokenRequest: TokenRequest): OAuth2Authentication {

        // check token with google here

        return super.getOAuth2Authentication(client, tokenRequest)
    }

    companion object {
        const val GRANT_TYPE = "google"
    }
}

客户端移动应用程序必须以这种方式发送请求:

发布 / oauth /令牌

有效载荷:

{
  "grant_type": "google"
  "username": "admin"
  "token": "xxxxxxxxxxxxxxxxxxxxx" 
}

不要忘记将带有客户端凭据的授权标头也发送到 Spring 验证允许的大类型、范围等


推荐阅读