配置项目的注意点
- 在集成登录时,需要在谷歌的云平台创建一个项目,在此项目中配置下redirect_uri、权限等信息。
- 创建完项目后,将client_id和client_secret保存下来,后面集成时需要使用。
集成谷歌登录的时序图
流程关键点解释
-
在需要集成谷歌登录的系统的登录页面添加一个谷歌登录按钮,点击此按钮跳转到
https://accounts.google.com/o/oauth2/v2/auth?client_id=123456-sskjaksj2332jkdjkds99339wowiei.apps.googleusercontent.com&redirect_uri=https://localhost:8080/page/main&scope=openid%20profile%20email&response_type=code
这个地址,这个地址会进入谷歌的登录页面。 -
当用户输入完谷歌账号和密码,登录完成后,谷歌会重定向到我们提供给谷歌的重定向地址,这里给个我重定向后的地址示例
https://localhost:8080/page/main?code=4%2F0AfJohXksR-Dkt_uO0Sg2ThXm-VMlXTN_9Yp4XzZQa5FvpeMUesvFYiB1e8-35ocews2riQ&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=consent
在重定向页面可以拿到code,我们就可以拿着这个code传给后端的接口。 -
当后端拿到前端传过来的code后,需要先调用接口获取到accessToken,再拿着accessToken去请求接口获取用户信息
-
获取accessToken的接口地址是
https://oauth2.googleapis.com/token
,POST请求,使用RestTemplate请求的示例代码如下;官方接口介绍/** * 获取accessToken * 接口官方地址:https://developers.google.com/identity/openid-connect/openid-connect?hl=zh-cn#discovery * * @param certificate * @param oauthClientDetails * @return */ private AccessTokenResult accessToken(Certificate certificate, OauthClientDetails oauthClientDetails) { Map<String, String> uriVariables = new HashMap<>(5); uriVariables.put("redirect_uri", certificate.getRedirectUri()); uriVariables.put("code", certificate.getCode()); uriVariables.put("client_id", oauthClientDetails.getClientId()); uriVariables.put("client_secret", oauthClientDetails.getClientSecret()); uriVariables.put("grant_type", "authorization_code"); String data = toUrlData(uriVariables); HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/x-www-form-urlencoded"); HttpEntity<String> httpEntity = new HttpEntity<>(data, headers); AccessTokenResult accessTokenResult = restTemplate.postForObject(ACCESS_TOKEN_URL, httpEntity, AccessTokenResult.class); log.info("获取到Google的token为{}", accessTokenResult); if (accessTokenResult == null || StringUtils.isBlank(accessTokenResult.getAccessToken())) { log.error("Google授权登陆失败,无法通过授权码获取信息 {}", accessTokenResult); throw new BusinessException(ResultCodeEnum.OAUTH_REQ_ERROR); } return accessTokenResult; } private String toUrlData(Map<String, String> params) { StringJoiner data = new StringJoiner("&"); Iterator<Map.Entry<String, String>> it = params.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> next = it.next(); data.add(next.getKey() + "=" + next.getValue()); } return data.toString(); } @Data @ToString public static class AccessTokenResult { @JsonAlias("access_token") private String accessToken; @JsonAlias("id_token") private String idToken; @JsonAlias("error") private String error; @JsonAlias("error_description") private String errorDescription; }
-
获取用户信息的接口地址是
https://www.googleapis.com/oauth2/v3/userinfo
,GET请求,使用RestTemplate请求的示例代码如下;官方接口介绍/** * 获取用户信息 * * @param accessToken * @return */ private InnerUserInfo innerUserInfo(String accessToken) { String authorization = "Bearer " + accessToken; HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", authorization); HttpEntity<String> requestEntity = new HttpEntity<>(null, headers); InnerUserInfo innerUserInfo = restTemplate.exchange(USER_INFO_URL, requestEntity, InnerUserInfo.class); log.info("获取到Google的用户信息为{}", innerUserInfo); if (innerUserInfo == null) { log.warn("Google 无法获取用户信息"); innerUserInfo = new InnerUserInfo(); } if (StringUtils.isBlank(innerUserInfo.getName())) { log.warn("Google 无法获取用户信息 {}", innerUserInfo); } return innerUserInfo; } /** * 返回结果示例: * HTTP/1.1 200 OK * Content-Type: application/json * <p> * { * "sub": "248289761001", * "name": "Jane Doe", * "given_name": "Jane", * "family_name": "Doe", * "preferred_username": "j.doe", * "email": "janedoe@example.com", * "picture": "http://example.com/janedoe/me.jpg" * } * 官方地址:https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse */ @Data @ToString public static class InnerUserInfo { @JsonAlias("sub") private String sub; @JsonAlias("name") private String name; @JsonAlias("given_name") private String givenName; @JsonAlias("family_name") private String familyName; @JsonAlias("preferred_username") private String preferredUsername; @JsonAlias("email") private String email; @JsonAlias("picture") private String picture; }
-