首页 > 解决方案 > Spring Boot 社交登录和谷歌日历 API

问题描述

问题

通过 Spring Security OAuth2 重用最终用户 Google 身份验证以在 Web 应用程序中访问 Google 日历 API

描述

我能够通过 Spring Security 使用 Login 创建一个小型 Spring Boot Web 应用程序

应用程序.yaml

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: <id>
            client-secret: <secret>
            scope:
              - email
              - profile
              - https://www.googleapis.com/auth/calendar.readonly

当应用程序启动时,我可以访问http://localhost:8080/user并要求用户登录谷歌。成功登录后,配置文件 json 在浏览器中显示为以下响应:

安全控制器

@RestController
class SecurityController {
    @RequestMapping("/user")
    fun user(principal: Principal): Principal {
        return principal
    }
}

安全配置.kt

@Configuration
class SecurityConfiguration : WebSecurityConfigurerAdapter() {
    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login()
    }
}

问题

我想重用此身份验证来检索所有用户的日历事件。以下代码取自谷歌关于访问日历 API 的教程,但它创建了一个完全独立的授权流程并要求用户登录。

    @Throws(IOException::class)
    private fun getCredentials(httpTransport: NetHttpTransport): Credential {
        val clientSecrets = loadClientSecrets()
        return triggerUserAuthorization(httpTransport, clientSecrets)
    }

    private fun loadClientSecrets(): GoogleClientSecrets {
        val `in` = CalendarQuickstart::class.java.getResourceAsStream(CREDENTIALS_FILE_PATH)
                ?: throw FileNotFoundException("Resource not found: $CREDENTIALS_FILE_PATH")
        return GoogleClientSecrets.load(JSON_FACTORY, InputStreamReader(`in`))
    }

    private fun triggerUserAuthorization(httpTransport: NetHttpTransport, clientSecrets: GoogleClientSecrets): Credential {
        val flow = GoogleAuthorizationCodeFlow.Builder(
                httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(FileDataStoreFactory(File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build()
        val receiver = LocalServerReceiver.Builder().setPort(8880).build()
        return AuthorizationCodeInstalledApp(flow, receiver).authorize("user")
    }

如何重复使用已完成的身份验证来访问最终用户在 Google 帐户上的日历活动?

标签: spring-bootgoogle-calendar-apigoogle-oauthspring-security-oauth2google-signin

解决方案


如果我理解正确,您的意思是重用身份验证是您想要使用 Spring 为您检索到的访问和刷新令牌,以便将它们用于针对 Google API 的请求。

可以将用户身份验证详细信息注入到端点方法中,如下所示:

import org.springframework.security.oauth2.client.OAuth2AuthorizedClient
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class FooController(val historyService: HistoryService) {

    @GetMapping("/foo")
    fun foo(@RegisteredOAuth2AuthorizedClient("google") user: OAuth2AuthorizedClient) {
        user.accessToken
    }

}

有了这些详细信息,OAuth2AuthorizedClient您应该能够使用 google API 做任何您需要的事情。

如果您需要在没有用户向您的服务发出请求的情况下访问 API,您可以注入OAuth2AuthorizedClientService托管组件,并像这样使用它:

import org.springframework.security.oauth2.client.OAuth2AuthorizedClient
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService
import org.springframework.stereotype.Service

@Service
class FooService(val clientService: OAuth2AuthorizedClientService) {

    fun foo() {
        val user = clientService.loadAuthorizedClient<OAuth2AuthorizedClient>("google", "principal-name")
        user.accessToken
    }

}

推荐阅读