google-idtoken验证

This commit is contained in:
2025-06-12 18:16:24 +08:00
committed by khalil
parent cb86e2da01
commit ce7b641e73
7 changed files with 187 additions and 25 deletions

View File

@@ -29,6 +29,28 @@
<artifactId>accompany-sharding-service</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>2.7.0</version> <!-- 建议使用最新版本 -->
</dependency>
<!-- gRPC 核心库提供Context类 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-core</artifactId>
<version>1.71.0</version> <!-- 使用最新稳定版 -->
</dependency>
<!-- OpenCensus解决trace相关错误 -->
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>0.31.1</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>0.31.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,90 @@
package com.accompany.core.service;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
@Slf4j
@Service
public class GoogleTokenVerifier {
private final GoogleIdTokenVerifier verifier;
private final String clientId;
public GoogleTokenVerifier(NetHttpTransport transport, GsonFactory jsonFactory, String clientId) {
this.clientId = clientId;
this.verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singletonList(clientId))
.build();
}
/**
* 验证Token并返回用户信息
*/
public GoogleUserInfo verifyAndGetUserInfo(String idTokenString) {
try {
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken == null) {
throw new IllegalArgumentException("Invalid ID token");
}
GoogleIdToken.Payload payload = idToken.getPayload();
return new GoogleUserInfo(
payload.getSubject(),
payload.getEmail(),
(String) payload.get("name"),
(String) payload.get("picture")
);
} catch (GeneralSecurityException e) {
log.error("verifyAndGetUserInfo:e:{}", e.getMessage(), e);
} catch (IOException e) {
log.error("verifyAndGetUserInfo:e:{}", e.getMessage(), e);
} catch (IllegalArgumentException e) {
log.error("verifyAndGetUserInfo:e:{}", e.getMessage(), e);
}
return null;
}
/**
* 仅获取用户邮箱
*/
public String getEmailFromToken(String idTokenString) {
return verifyAndGetUserInfo(idTokenString).getEmail();
}
/**
* 仅获取用户ID
*/
public String getUserIdFromToken(String idTokenString) {
return verifyAndGetUserInfo(idTokenString).getUserId();
}
/**
* 用户信息DTO
*/
public static class GoogleUserInfo {
private final String userId;
private final String email;
private final String name;
private final String pictureUrl;
public GoogleUserInfo(String userId, String email, String name, String pictureUrl) {
this.userId = userId;
this.email = email;
this.name = name;
this.pictureUrl = pictureUrl;
}
// Getters
public String getUserId() { return userId; }
public String getEmail() { return email; }
public String getName() { return name; }
public String getPictureUrl() { return pictureUrl; }
}
}

View File

@@ -0,0 +1,33 @@
package com.accompany.core.service.user;
import com.accompany.core.service.GoogleTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class GoogleAuthConfig {
@Value("${google-auth.client-id}")
private String clientId;
@Bean
public NetHttpTransport netHttpTransport() {
return new NetHttpTransport();
}
@Bean
public GsonFactory gsonFactory() {
return new GsonFactory();
}
@Bean
public GoogleTokenVerifier googleTokenVerifier(NetHttpTransport transport, GsonFactory jsonFactory) {
return new GoogleTokenVerifier(transport, jsonFactory, clientId);
}
}

View File

@@ -1,11 +1,12 @@
package com.accompany.core.service.user.impl;
import com.accompany.common.utils.GoogleJwtParser;
import com.accompany.common.utils.StringUtils;
import com.accompany.core.model.GoogleOpenidRef;
import com.accompany.core.mybatismapper.GoogleOpenidRefMapper;
import com.accompany.core.service.GoogleTokenVerifier;
import com.accompany.core.service.user.GoogleOpenidRefService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@@ -21,20 +22,23 @@ import java.util.Optional;
public class GoogleOpenidRefServiceImpl extends ServiceImpl<GoogleOpenidRefMapper, GoogleOpenidRef> implements GoogleOpenidRefService {
@Autowired
private GoogleTokenVerifier googleTokenVerifier;
@Override
public String getUnionIdByEmail(String email, String idToken) {
GoogleOpenidRef googleOpenidRef = baseMapper.selectById(email);
return Optional.ofNullable(googleOpenidRef)
.map(x -> x.getOpenId())
.orElseGet(() -> {
String sub = GoogleJwtParser.getSubFromToken(idToken);
if (StringUtils.isNotEmpty(sub)) {
saveRecord(email, sub);
return sub;
GoogleTokenVerifier.GoogleUserInfo sub = googleTokenVerifier.verifyAndGetUserInfo(email);
if (sub != null && StringUtils.isNotEmpty(sub.getUserId()) && email.equals(sub.getEmail())) {
String userId = sub.getUserId();
saveRecord(email, userId);
return userId;
}
return null;
});
}
@Override