【问题标题】:Google's Refresh Access token Api not working from SpringBoot谷歌的刷新访问令牌 API 在 SpringBoot 中不起作用
【发布时间】:2020-03-11 09:44:40
【问题描述】:

我正在尝试构建一个使用一些基本谷歌日历 API 的小型应用程序。由于生成的访问令牌每 60 分钟过期一次,因此我想自动调用刷新访问令牌 api 并将旧的访问令牌替换为新的访问令牌。

为此,我调用以下 api:

POST /o/oauth2/token?client_id={clientId}
&client_secret={secret}
&grant_type=refresh_token
&access_type=offline
&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar
&refresh_token={refreshToken} HTTP/1.1

Host: accounts.google.com
User-Agent: PostmanRuntime/7.19.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 4a8e2563-4e31-431d-9e19-a442fb419590,1f750768-a6f5-42de-9f52-05555ac79c01
Host: accounts.google.com
Accept-Encoding: gzip, deflate
Content-Length: 0
Connection: keep-alive
cache-control: no-cache

我尝试从邮递员那里调用这个 api,它工作得很好,但是当我通过 Spring boot 尝试同样的操作时,我收到 400 Bad Request 错误。下面是我用来测试不同场景的代码。

HttpHeaders requestHeaders = new HttpHeaders();
    requestHeaders.add("Accept", "*/*");
    requestHeaders.add("Host", "accounts.google.com");
    //requestHeaders.add("User-Agent", "HTTPie/0.6.0");
    requestHeaders.add("Accept-Encoding", "*/*");
    requestHeaders.add("Content-Type",  "application/x-www-form-urlencoded; charset=utf-8");
    HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
    String REFRESH_TOKEN_URL = "https://accounts.google.com/o/oauth2/token?"+
        "client_id={exact same client id}" +
        "&client_secret={exact same client secret}" +
        "&grant_type=refresh_token" +
        "&access_type=offline" +
        "&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar" +
        "&refresh_token={exact same refresh token}";
    ResponseEntity<Object> response = restTemplate.exchange(REFRESH_TOKEN_URL, HttpMethod.POST, requestEntity, Object.class);


我不知道我在这里做错了什么。 请帮我解决这个问题(我已经被困了超过 1 天)。

P.S : 我可能必须将此代码集成到我公司的产品中,并且无法使用 google 客户端 sdk。这就是我尝试探索 api 选项的原因。

【问题讨论】:

    标签: java spring-boot google-api google-calendar-api google-authentication


    【解决方案1】:

    完成你想做的事。您可以使用Google API Client Library for Java,它将帮助您设置accessToken和refreshToken,并能够更轻松地处理它们。

    查看我从Java Calendar Quickstart 获取的代码(稍作修改),它可以帮助您调用 Google 日历 API:

    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.*;
    
    public class Main {
    
        private static final String APPLICATION_NAME = "Google Calendar API Java";
        private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
        private static final String TOKENS_DIRECTORY_PATH = "tokens";
    
        /**
         * Global instance of the scopes required by this quickstart.
         * If modifying these scopes, delete your previously saved tokens/ folder.
         */
        private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);
        private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
    
        /**
         * Creates an authorized Credential object.
         * @param HTTP_TRANSPORT The network HTTP Transport.
         * @return An authorized Credential object.
         * @throws IOException If the credentials.json file cannot be found.
         */
        private static Credential getCredentials(NetHttpTransport HTTP_TRANSPORT) throws Exception {
            // Load client secrets.
            InputStream in = Calendar.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
            if (in == null) {
                throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
            }
            GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
    
            // System.out.println(clientSecrets.getDetails());
            // Build flow and trigger user authorization request.
            GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                    HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                    .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                    .setAccessType("offline")
                    .build();
            LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
            return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
        }
    
        public static void main(String[] args) throws Exception {
            // Build a new authorized API client service.
            final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            Credential credentials = getCredentials(HTTP_TRANSPORT);
    
    
            Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credentials)
                    .setApplicationName(APPLICATION_NAME)
                    .build();
            Events events = service.events().list("primary").execute();
            List<Event> items = events.getItems();
            if (items.isEmpty()) {
                System.out.println("No events found.");
            } else {
                System.out.println("events found.");
                for(Event event: items){
                    System.out.println(event.getSummary());
                }
            }
    
        }
    }
    

    这些是我使用的 Maven 依赖项,以防您更喜欢 Maven,而不是快速入门中显示的 Gradle:

    <dependencies>
            <!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-admin-directory -->
            <dependency>
                <groupId>com.google.apis</groupId>
                <artifactId>google-api-services-admin-directory</artifactId>
                <version>directory_v1-rev110-1.25.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-calendar -->
            <dependency>
                <groupId>com.google.apis</groupId>
                <artifactId>google-api-services-calendar</artifactId>
                <version>v3-rev379-1.25.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.9</version>
            </dependency>
            <dependency>
                <groupId>org.joda</groupId>
                <artifactId>joda-beans</artifactId>
                <version>2.7.1</version>
            </dependency>
            <dependency>
                <groupId>com.google.gdata</groupId>
                <artifactId>core</artifactId>
                <version>1.47.1</version>
            </dependency>
        </dependencies>
    

    通知

    记得将 credentials.json 文件放在您的 resources 文件夹中。

    【讨论】:

    • 实际上我尝试运行的代码可能用于我公司的微服务中,我认为他们不允许使用客户端库。所以这就是我试图查看 api 路由的原因。
    猜你喜欢
    • 2017-04-19
    • 2013-07-20
    • 1970-01-01
    • 2021-05-06
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 2021-01-29
    相关资源
    最近更新 更多