Google OAuth 2.0 是一種安全協議,用於向第三方應用程序授予訪問用戶資源的權限,而無需向第三方應用程序透露用戶的憑據。以下是實現 Google OAuth 2.0 登入與註冊的步驟:
- 在 Google Cloud Platform (GCP)上註冊 Oauth 2.0 應用
- 建立專案(如果還沒有專案的話)
- 進入專案
- 選擇 API和服務
- 選擇 憑證
- 建立憑證,選擇 OAuth用戶端ID
- 應用程式類型選擇網頁應用程式,名稱隨便打方便確認就好,然後填寫已授權的 JavaScript 來源與已授權的重新導向 URI,例如說你如果在local上開發,那已授權的 JavaScript 來源可以寫http://localhost:9000(port自己調整),已授權的重新導向 URI可以寫http://localhost:9000/GoogleAuthRedirect(反正就看你要重新導向到哪個path),好了之後建立
- 把該憑證的client_id跟client_secret存起來
- 前端實現 Google OAuth 2.0 登入
- 發起 Google 登入請求,當用戶點擊「使用 Google 登入」按鈕時,將用戶重定向到 Google 的授權頁面。
- 捕獲授權碼並發送到後端,在重定向 URI 頁面上捕獲授權碼(authorizationCode),並將其發送到後端進行處理。
- 後端處理授權碼
- 用授權碼向google取得access token
- 更新DB
以下代碼使用的僅供參考,環境是使用vue3+ springbott + java17,以及實作過程中要注意的點:
1. 授權碼無法正確交換令牌
確認 Google Cloud Console 中配置的重定向 URI 是否與應用程序中的一致,後端的 redirect_uri 值需要設定成已授權的重新導向 URI的值
確認 client_id 和 client_secret 是否正確
2. 用戶已存在的處理
3. 確認access token,傳遞時使用https,憑證資訊千萬別hard code
//前端實現 Google OAuth 2.0 登入
const loginWithGoogle = async () => {
const GOOGLE_CLIENT_ID = 'YOUR_GOOGLE_CLIENT_ID';
const GOOGLE_REDIRECT_URI = 'http://localhost:9000/GoogleAuthRedirect';
window.location.href = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=${GOOGLE_REDIRECT_URI}&response_type=code&scope=openid%20email%20profile&access_type=offline&prompt=consent`;
};
// 在重定向 URI 的 JavaScript 文件中
const getAuthorizationCode = () => {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('code');
};
const sendAuthorizationCode = async (authorizationCode) => {
try {
//請自行定義要打到後端的path
const response = await axios.post('/api/auth/google-auth', { code: authorizationCode });
console.log('Authorization successful:', response.data);
} catch (error) {
console.error('Authorization failed:', error);
}
};
const authorizationCode = getAuthorizationCode();
if (authorizationCode) {
sendAuthorizationCode(authorizationCode);
}
//後端處理授權碼
@RestController
@RequestMapping("/api/auth")
public class GoogleAuthController {
@Value("${google.client.id}")
private String clientId;
@Value("${google.client.secret}")
private String clientSecret;
@Autowired
private GoogleAuthService googleAuthService;
@PostMapping("/google-auth")
public ResponseEntity<?> handleAuthorizationCode(@RequestBody AuthorizationCodeRequest request) {
String authorizationCode = request.getCode();
String tokenUrl = "https://oauth2.googleapis.com/token";
RestTemplate restTemplate = new RestTemplate();
Map<String, String> requestBody = new HashMap<>();
requestBody.put("code", authorizationCode);
requestBody.put("client_id", clientId);
requestBody.put("client_secret", clientSecret);
requestBody.put("redirect_uri", "http://localhost:9000/GoogleAuthRedirect");
requestBody.put("grant_type", "authorization_code");
try {
ResponseEntity<Map> responseEntity = restTemplate.postForEntity(tokenUrl, requestBody, Map.class);
Map<String, Object> responseBody = responseEntity.getBody();
String accessToken = (String) responseBody.get("access_token");
String userInfoUrl = "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + accessToken;
ResponseEntity<Map> userInfoResponse = restTemplate.getForEntity(userInfoUrl, Map.class);
Map<String, Object> userInfo = userInfoResponse.getBody();
String email = (String) userInfo.get("email");
Boolean isSuccess = googleAuthService.registerGoogleUser(email);
return ResponseEntity.ok(userInfo);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to authenticate with Google");
}
}
static class AuthorizationCodeRequest {
private String code;
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
}
}
//更新DB
@Service
public class GoogleAuthService {
@Autowired
private UserRepository userRepository;
public Boolean registerGoogleUser(String email) {
if (userRepository.existsByEmail(email)) {
return false;
}
User user = new User();
user.setEmail(email);
userRepository.save(user);
return true;
}
}