我正在尝试构建一个使用一些基本的Google日历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 client sdk。这就是为什么我试图探索api选项的原因。
完成您想做的事情。您可以使用Google API Client Library for Java,它将帮助您设置accessToken和refreshToken并能够更轻松地处理它们。
检查我从Java Calendar Quickstart中获得的此代码(进行了一些小的修改),它可以帮助您调用Google Calendar 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,而不是快速入门中出现的Graddle:
<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文件夹中。