如何使用推送通知同步 Google 日历事件?

问题描述 投票:0回答:1

我已经完成了手表功能的实现,并且也成功实现了接收推送通知。不过我想在收到推送通知后同步日历,但是这里失败了。

我的应用程序是一个Web服务器应用程序,所以我使用servlet实现了google oauth2登录和回调。

我参考的实现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应用程序,所以我参考了以下文档。

spring-boot google-oauth google-calendar-api
1个回答
0
投票

问题是项目的重定向 uri 未添加到 API 密钥的 redirect_uris 中。添加后,问题就解决了。

我不会删除帖子,因为可能有人和我有同样的问题。

© www.soinside.com 2019 - 2024. All rights reserved.