我已经完成了手表功能的实现,并且也成功实现了接收推送通知。不过我想在收到推送通知后同步日历,但是这里失败了。
我的应用程序是一个Web服务器应用程序,所以我使用servlet实现了google oauth2登录和回调。
我将提供解释以及代码。
@WebServlet(urlPatterns = "/oauth2Login")
public class GoogleAuthenticationServlet extends AbstractAuthorizationCodeServlet {
@Override
protected AuthorizationCodeFlow initializeFlow() {
return GoogleApiConfig.initializeFlow();
}
@Override
protected String getRedirectUri(HttpServletRequest httpServletRequest) {
return GoogleApiConfig.getRedirectUri(httpServletRequest);
}
@Override
protected String getUserId(HttpServletRequest httpServletRequest) {
return GoogleApiConfig.getClientId(httpServletRequest);
}
}
@WebServlet(urlPatterns = "/oauth2callback")
public class Oauth2CallbackServlet extends AbstractAuthorizationCodeCallbackServlet {
@Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws IOException {
String userId = req.getSession().getId();
resp.sendRedirect("/google/watch?userId=" + userId + "&accessToken=" + credential.getAccessToken());
}
...
@Override
protected String getUserId(HttpServletRequest var1) {
return GoogleApiConfig.getClientId(var1);
}
}
@GetMapping("/google/watch")
public ResponseEntity<Channel> watchCalendar(@RequestParam String userId,
@RequestParam String accessToken) {
accessToken = "Bearer " + accessToken;
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", accessToken);
Channel channel = adateService.executeWatchRequest(userId);
return ResponseEntity.ok()
.headers(headers)
.body(channel);
}
@PostMapping("/notifications")
public ResponseEntity<List<GoogleCalendarEventResponse>> printNotification(@RequestHeader(WebhookHeaders.RESOURCE_ID) String resourceId,
@RequestHeader(WebhookHeaders.RESOURCE_URI) String resourceUri,
@RequestHeader(WebhookHeaders.CHANNEL_ID) String channelId,
@RequestHeader(WebhookHeaders.CHANNEL_EXPIRATION) String channelExpiration,
@RequestHeader(WebhookHeaders.RESOURCE_STATE) String resourceState,
@RequestHeader(WebhookHeaders.MESSAGE_NUMBER) String messageNumber,
HttpServletRequest request) {
log.info("Request for calendar sync, channelId=" + channelId + ", expiration=" + channelExpiration + ", messageNumber=" + messageNumber);
String userId = request.getSession().getId();
adateService.listEvents(userId);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
我检查了手表和推送的日志,都成功了。
{
"expiration": 1714380331000,
"id": "<id>",
"kind": "api#channel",
"resourceId": "<resourceId>",
"resourceUri": "https://www.googleapis.com/calendar/v3/calendars/primary/events?alt=json",
"token": "tokenValue"
}
2024-03-30T08:06:08.102Z INFO 957 --- [nio-8080-exec-1] c.f.d.a.c.i.GoogleCalendarControllerImpl : Request for calendar sync, channelId=<calendar-id>, expiration=Mon, 29 Apr 2024 06:30:11 GMT, messageNumber=<message-number>
@Transactional
public void listEvents(String sessionId) {
try {
Calendar calendar = googleApiConfig.calendarService(sessionId);
Calendar.Events.List request = calendar.events().list("primary");
String syncToken = getNextSyncToken();
List<Event> events;
if (syncToken == null) {
events = request.execute().getItems();
} else {
request.setSyncToken(syncToken);
events = request.execute().getItems();
googleApiConfig.getSyncSettingsDataStore().set(SYNC_TOKEN_KEY, syncToken);
}
syncEvents(events);
} catch (IOException e) {
throw new AdateIOException(e);
}
}
---
public Calendar calendarService(String sessionId) {
Credential credential = getCredentials(sessionId);
return new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
---
public DataStore<String> getSyncSettingsDataStore() {
return syncSettingsDataStore;
}
I initialized syncSettingsDataStore using the @PostConstruct annotation
syncSettingsDataStore = GoogleApiConfig.getDataStoreFactory().getDataStore("SyncSettings");
查看日志后,事件同步代码中出现错误,并已识别出以下错误消息。
403 Forbidden<EOL>GET https://www.googleapis.com/calendar/v3/calendars/primary/events<EOL>{<EOL> "code" : 403,<EOL> "errors" : [ {<EOL> "domain" : "global",<EOL> "message" : "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",<EOL> "reason" : "forbidden"<EOL> } ],<EOL> "message" : "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",<EOL> "status" : "PERMISSION_DENIED"<EOL>}]
检查错误代码后,我发现了消息“请使用 API Key 或其他形式的 API”,这让我考虑将 accessToken 作为参数传递。但是,我不知道如何将 accessToken 作为推送通知的参数传递,因此无法实现它。
我已阅读这篇文章,但我仍然无法理解它。
它让我发疯......!!!!!
我对在 Stack Overflow 上发布问题还是个新手,所以如果有任何不正确的信息或者您需要更多详细信息,请随时发表评论。
我的服务是一个Web应用程序,所以我参考了以下文档。
问题是项目的重定向 uri 未添加到 API 密钥的 redirect_uris 中。添加后,问题就解决了。
我不会删除帖子,因为可能有人和我有同样的问题。