0

I have problem extending the standard one hour for validity of google access token. One part of my code is getting authorization from the user, using the GoogleAuthorizationCodeFlow as per Google recommendation. This works fine and gives me a TokenResponse that I persist to be used in an other part of the application where the user is not connected.

As per Google documentation, I thought that the "offline" access type in the flow would enable the TokenResponse to be usable as longer as the user doesnt revoke it. But apparently when I use this TokenReponse just after the user authorization, it works fine but when I use it after more than one hour, I get an "invalid credentials" sent back by Google.

Here is the code which creates the TokenResponse once the user has authorized it :

private HttpTransport HTTP_TRANSPORT;
private JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

private static GoogleAuthorizationCodeFlow flow;

@PostConstruct
public void init() {
    try {

        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
    } catch (GeneralSecurityException | IOException e) {
        logger.info(String.format("Raised Exception while getting GoogleNetHttpTransport : %s", e.getMessage()));
        e.printStackTrace();
    }
    flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, APP_ID, APP_SECRET,
            Collections.singleton(CalendarScopes.CALENDAR_READONLY)).setAccessType("offline").build();
}
@RequestMapping(value = Uris.GOOGLERD)
public ModelAndView googleCallBack(HttpServletRequest request, @RequestParam(value = "state", required = false) String state,
        @RequestParam(value = "code", required = false) String code,
        @RequestParam(value = "error", required = false) String error, Model model) {
    DynSubscriber dynSubscriber = (DynSubscriber) request.getSession().getAttribute("dynSubscriber");
    ModelAndView toReturn = new ModelAndView("confirmation");
    toReturn.addObject("buttonLabel", "Accueil");

    try {

        AuthorizationCodeTokenRequest tokenRequest = flow.newTokenRequest(code);
        TokenResponse tr = tokenRequest.setRedirectUri(request.getRequestURL().toString()).execute();


        // Json Conversion of Token Response for future use
        StringWriter jsonTrWriter = new StringWriter();
        JsonGenerator generator = JSON_FACTORY.createJsonGenerator(jsonTrWriter);
        generator.serialize(tr);
        generator.flush();
        generator.close();


        //Persists google access info 
        dynSubOp.setSPConnexionInfo(dynSubscriber, jsonTrWriter.toString(), DynServiceProviderType.GOOGLECAL);
        toReturn.addObject("message","Agenda Google autorisé");

    } catch (IOException | DynServicesException e) {
        logger.error(String.format("Exception raised in googleCallBack for subscriber %s : %s", dynSubscriber.buildFullName(), e.getMessage()),e);
        toReturn.addObject("message", "Problème lors du processus d'autorisation google");
    }

    return toReturn;
}
}

And here is the offline code which uses this TokenReponse :

private com.google.api.services.calendar.Calendar calendarConnection;


public DynGoogleCalendarRetriever(String subid, String connectionInformation)
        throws CalendarConnectionNotAuthorizedException {


    TokenResponse tr;
    try {
        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        tr = JSON_FACTORY.fromString(connectionInformation, TokenResponse.class);

        Credential c = new GoogleCredential().setFromTokenResponse(tr);
        calendarConnection = new com.google.api.services.calendar.Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, c)
                .build();
    } catch (IOException | GeneralSecurityException e) {
        logger.error(String.format("Failure creating the credentials for subscriber id %s", subid), e);
        throw new CalendarConnectionNotAuthorizedException(String.format(
                "Failure creating the credentials for subscriber id %s", subid), e);
    }


}
4

1 回答 1

0

看起来这已经在另一个 SO question中得到了回答。要获得启用我想要的刷新令牌,我需要使用approval_prompt=force 参数(builder.setApprovalPrompt("force"))构建流程

根据评论,这需要在流程初始化中完成的离线访问。

然而,一个补充:尽管我从谷歌文档(可能是旧版本)复制并粘贴了它,但我的问题中的离线代码不起作用。Credential 需要使用它的 Builder 对象。

这是功能齐全的离线代码:

    TokenResponse tr;
    try {
        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        tr = JSON_FACTORY.fromString(connectionInformation, TokenResponse.class);

        Credential c = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT).setJsonFactory(JSON_FACTORY)
                .setClientSecrets(APP_ID, APP_SECRET).build().setFromTokenResponse(tr);

        calendarConnection = new com.google.api.services.calendar.Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, c)
                .build();
    } catch (IOException | GeneralSecurityException e) {
        logger.error(String.format("Failure creating the credentials for subscriber id %s", subid), e);
        throw new CalendarConnectionNotAuthorizedException(String.format(
                "Failure creating the credentials for subscriber id %s", subid), e);
    }
于 2013-12-19T08:53:24.833 回答