更换谷歌登录token解析方式
This commit is contained in:
@@ -40,7 +40,7 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
registry.addInterceptor(jwtInterceptor)
|
registry.addInterceptor(jwtInterceptor)
|
||||||
.addPathPatterns("/api/**/**") // 保护这些路径
|
.addPathPatterns("/api/**/**") // 保护这些路径
|
||||||
.excludePathPatterns(Arrays.asList("/api/auth/precheckEmail", "/api/auth/registerOrLogin",
|
.excludePathPatterns(Arrays.asList("/api/auth/precheckEmail", "/api/auth/registerOrLogin",
|
||||||
"/api/auth/forgotPwd", "/api/style/callback", "/api/auth/parseGoogleCredential")); // 排除登录接口
|
"/api/auth/forgotPwd", "/api/style/callback", "/api/auth/parseGoogleAccessToken")); // 排除登录接口
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -106,10 +106,19 @@ public class LoginController {
|
|||||||
* 前端直接将credential传给服务端验证
|
* 前端直接将credential传给服务端验证
|
||||||
* 服务端直接解析和验证JWT,无需与Google服务器交换
|
* 服务端直接解析和验证JWT,无需与Google服务器交换
|
||||||
*/
|
*/
|
||||||
@CrossOrigin
|
// @GetMapping("/parseGoogleCredential")
|
||||||
@GetMapping("/parseGoogleCredential")
|
|
||||||
public ApiResponse<LoginVO> parseGoogleCredential(@RequestParam("credential") String credential) throws ParseException, IOException, JOSEException {
|
public ApiResponse<LoginVO> parseGoogleCredential(@RequestParam("credential") String credential) throws ParseException, IOException, JOSEException {
|
||||||
return ApiResponse.success(loginService.parseGoogleCredential(credential));
|
return ApiResponse.success(loginService.parseGoogleCredential(credential));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用OAuth 2.0方式登录
|
||||||
|
* @param accessToken 前端通过Google回调获取的token
|
||||||
|
* @return 用户登录信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/parseGoogleAccessToken")
|
||||||
|
public ApiResponse<LoginVO> parseGoogleAccessToken(@RequestParam("accessToken") String accessToken) {
|
||||||
|
return ApiResponse.success(loginService.parseGoogleAccessToken(accessToken));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,4 +34,6 @@ public interface LoginService extends IService<User> {
|
|||||||
User getUserInfo();
|
User getUserInfo();
|
||||||
|
|
||||||
LoginVO parseGoogleCredential(String credential) throws ParseException, JOSEException, IOException;
|
LoginVO parseGoogleCredential(String credential) throws ParseException, JOSEException, IOException;
|
||||||
|
|
||||||
|
LoginVO parseGoogleAccessToken(String accessToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.aida.lanecarford.common.enums.LanguageEnum;
|
|||||||
import com.aida.lanecarford.common.response.ResultEnum;
|
import com.aida.lanecarford.common.response.ResultEnum;
|
||||||
import com.aida.lanecarford.common.security.JwtUtil;
|
import com.aida.lanecarford.common.security.JwtUtil;
|
||||||
import com.aida.lanecarford.common.security.context.UserContext;
|
import com.aida.lanecarford.common.security.context.UserContext;
|
||||||
|
import com.aida.lanecarford.dto.GoogleUser;
|
||||||
import com.aida.lanecarford.dto.LoginRequest;
|
import com.aida.lanecarford.dto.LoginRequest;
|
||||||
import com.aida.lanecarford.entity.User;
|
import com.aida.lanecarford.entity.User;
|
||||||
import com.aida.lanecarford.exception.BusinessException;
|
import com.aida.lanecarford.exception.BusinessException;
|
||||||
@@ -16,9 +17,11 @@ import com.aida.lanecarford.util.RandomsUtil;
|
|||||||
import com.aida.lanecarford.util.SendEmailUtil;
|
import com.aida.lanecarford.util.SendEmailUtil;
|
||||||
import com.aida.lanecarford.vo.AuthPrincipalVO;
|
import com.aida.lanecarford.vo.AuthPrincipalVO;
|
||||||
import com.aida.lanecarford.vo.LoginVO;
|
import com.aida.lanecarford.vo.LoginVO;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
|
||||||
import com.nimbusds.jose.JOSEException;
|
import com.nimbusds.jose.JOSEException;
|
||||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
import com.nimbusds.jose.jwk.JWK;
|
||||||
@@ -30,12 +33,13 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
|
|
||||||
import static com.aida.lanecarford.common.enums.AuthenticationOperationTypeEnum.*;
|
import static com.aida.lanecarford.common.enums.AuthenticationOperationTypeEnum.*;
|
||||||
|
|
||||||
@@ -58,6 +62,8 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
|||||||
private String googleClientId;
|
private String googleClientId;
|
||||||
@Value("${google.client_secret}")
|
@Value("${google.client_secret}")
|
||||||
private String googleClientSecret;
|
private String googleClientSecret;
|
||||||
|
@Value("${google.redirect_uri}")
|
||||||
|
private String googleRedirectUri;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -316,7 +322,72 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoginVO parseGoogleAccessToken(String accessToken) {
|
||||||
|
try {
|
||||||
|
log.info("accessToken: {}", accessToken);
|
||||||
|
// 使用 accessToken 获取 Google 用户信息
|
||||||
|
// GoogleUser googleUser = getGoogleUserFromCode(accessToken);
|
||||||
|
GoogleUser googleUser = getGoogleUserInfo(accessToken);
|
||||||
|
log.info("googleUser: {}", JSON.toJSONString(googleUser));
|
||||||
|
|
||||||
|
|
||||||
|
// 1. 根据用户邮箱查询是登录还是注册
|
||||||
|
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.lambda().eq(User::getEmail, googleUser.getEmail());
|
||||||
|
|
||||||
|
User user = getOne(queryWrapper);
|
||||||
|
AuthenticationOperationTypeEnum type = Objects.isNull(user) ? REGISTER: LOGIN;
|
||||||
|
LoginRequest loginRequest = new LoginRequest();
|
||||||
|
loginRequest.setName(googleUser.getName());
|
||||||
|
loginRequest.setEmail(googleUser.getEmail());
|
||||||
|
loginRequest.setOperationType(type.name());
|
||||||
|
|
||||||
|
return switch (type) {
|
||||||
|
case REGISTER -> register(loginRequest);
|
||||||
|
case LOGIN -> login(loginRequest);
|
||||||
|
default -> throw new BusinessException("Unknown authentication operation type.");
|
||||||
|
};
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BusinessException("Error processing Google login: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String TOKEN_URL = "https://oauth2.googleapis.com/token";
|
||||||
|
|
||||||
|
public GoogleUser getGoogleUserFromCode(String code) {
|
||||||
|
// Step 1: Exchange code for access_token
|
||||||
|
String accessToken = getAccessToken(code);
|
||||||
|
log.info("accessToken" + accessToken);
|
||||||
|
|
||||||
|
// Step 2: Use access_token to get Google User info
|
||||||
|
return getGoogleUserInfo(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAccessToken(String code) {
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("client_id", googleClientId);
|
||||||
|
params.put("client_secret", googleClientSecret);
|
||||||
|
params.put("redirect_uri", googleRedirectUri);
|
||||||
|
params.put("grant_type", "authorization_code");
|
||||||
|
params.put("code", code);
|
||||||
|
|
||||||
|
// 使用 RestTemplate 发起请求以获取 access_token
|
||||||
|
GoogleTokenResponse response = restTemplate.postForObject(TOKEN_URL, params, GoogleTokenResponse.class);
|
||||||
|
return response.getAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v3/userinfo";
|
||||||
|
private GoogleUser getGoogleUserInfo(String accessToken) {
|
||||||
|
/*System.setProperty("http.proxyHost", "127.0.0.1");
|
||||||
|
System.setProperty("http.proxyPort", "7890");
|
||||||
|
System.setProperty("https.proxyHost", "127.0.0.1");
|
||||||
|
System.setProperty("https.proxyPort", "7890");*/
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
String url = USER_INFO_URL + "?access_token=" + accessToken;
|
||||||
|
return restTemplate.getForObject(url, GoogleUser.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,4 +91,5 @@ webhook:
|
|||||||
|
|
||||||
google:
|
google:
|
||||||
client_id: 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
client_id: 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
client_secret: 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
|
client_secret: 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
|
||||||
|
redirect_uri: ${webhook.domain}/api/auth/google_callback
|
||||||
@@ -91,4 +91,5 @@ webhook:
|
|||||||
|
|
||||||
google:
|
google:
|
||||||
client_id: 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
client_id: 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
client_secret: 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
|
client_secret: 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
|
||||||
|
redirect_uri: ${webhook.domain}/api/auth/google_callback
|
||||||
Reference in New Issue
Block a user