Google的api调用支持oauth2和server account两种模式,但是第二种要配置G suit,整体来说比较复杂;而第一种,在线下开代理,登陆授权获得了auth code后,通过这个code拿refresh token却一直提示connection reset……
Connection reset出现的原因
- 如果一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer);
- 一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset)。
解决思路
-
跟源码,定位出现问题的那一步,具体是在获取到auth code后,去请求refresh token
-
初步定位是网络环境问题导致的,想到部署到Hongkong服务器上去做验证,需要用到本地浏览器,但是centos图形界面操作没用过,而且是线上服务不便重启切换
-
在www.v2ex.com/t/692540#re… 上,有朋友遇到类似问题,他提供的是python代理方案
import socks
import socket
socks.set_default_proxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1",1081)
socket.socket = socks.socksocket
- 随后找到Google playground可以在设置clientId和clientSecret之后,手动获取refresh token, 然后拿着这个可以在线上获取到access token, 示例代码如下:
import com.google.api.client.googleapis.auth.oauth2.GoogleRefreshTokenRequest;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import lombok.extern.slf4j.Slf4j;
import net.pailing.kandian.component.redis.client.RedisClientDecorate;
import net.pailing.kandian.component.util.env.EnvConfig;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author natsume
* @date 2020/9/14
*/
@Slf4j
@Component
public class AccessTokenHelper {
@Resource
RedisClientDecorate redisClient;
@Resource
EnvConfig envConfig;
private static final String CLIENT_ID_KEY = "google_client_id";
private static final String CLIENT_SECRET_KEY = "google_client_secret";
private static final String REFRESH_TOKEN_KEY = "google_refresh_token";
/**
* 获取access token
*
* @param refreshToken
* @param clientId
* @param clientSecret {
* "access_token": "ya29.a0AfH6SMDF0B2FEI3jHWPT5xxxxxxxxxxDeAZV3PXgQh9uyNzto",
* "expires_in": 3599,
* "scope": "https://www.googleapis.com/auth/admob.report",
* "token_type": "Bearer"
* }
* @return accessToken 3600s 过期
* @throws IOException
*/
private TokenResponse refreshAccessToken(String refreshToken, String clientId, String clientSecret)
throws IOException {
ArrayList<String> scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/admob.report");
TokenResponse tokenResponse =
new GoogleRefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(), refreshToken, clientId,
clientSecret).setScopes(scopes).setGrantType("refresh_token").execute();
log.info("tokenResponse:{}", tokenResponse);
redisClient.setWithExpire(buildGoogleAccessTokenKey(), tokenResponse, tokenResponse.getExpiresInSeconds());
return tokenResponse;
}
public TokenResponse getAccessToken() {
TokenResponse accessToken = redisClient.get(buildGoogleAccessTokenKey(), TokenResponse.class);
if (StringUtils.isEmpty(accessToken)) {
String refreshToken = envConfig.getProperty(REFRESH_TOKEN_KEY);
String clientId = envConfig.getProperty(CLIENT_ID_KEY);
String clientSecret = envConfig.getProperty(CLIENT_SECRET_KEY);
try {
accessToken = refreshAccessToken(refreshToken, clientId, clientSecret);
} catch (Exception e) {
log.error("Failed to get google oauth2 access token. refreshToken:{}, clientId:{}, secretSecret:{}",
refreshToken, clientId, clientSecret);
return null;
}
}
return accessToken;
}
private String buildGoogleAccessTokenKey() {
return "google_access_token";
}
}
- 最终,在Hongkong服务器下,终于获取到了access token,这期间也看了一遍源码,查了比较多的资料,感谢 V2EX平台@youthfire这位大佬的回复,以及提供了相关博客的广大博主。如果大家有相关问题,可以互相讨论学习。