GoogleTokenValidator.cs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. using System.Text.Json;
  2. using Application.Abstractions.Authentication;
  3. using Microsoft.Extensions.Logging;
  4. namespace Infrastructure.Authentication;
  5. internal sealed class GoogleTokenValidator(
  6. HttpClient httpClient,
  7. ILogger<GoogleTokenValidator> logger
  8. ) : IGoogleTokenValidator
  9. {
  10. public async Task<GoogleUserInfo?> ValidateAsync(string credential, string clientId, CancellationToken ct)
  11. {
  12. try
  13. {
  14. var response = await httpClient.GetAsync(
  15. $"https://oauth2.googleapis.com/tokeninfo?id_token={credential}", ct
  16. );
  17. if (!response.IsSuccessStatusCode)
  18. {
  19. logger.LogWarning("Google token validation failed: {StatusCode}", response.StatusCode);
  20. return null;
  21. }
  22. var json = await response.Content.ReadAsStringAsync(ct);
  23. var payload = JsonSerializer.Deserialize<JsonElement>(json);
  24. // aud (audience) 검증
  25. var aud = payload.GetProperty("aud").GetString();
  26. if (aud != clientId)
  27. {
  28. logger.LogWarning("Google token aud mismatch: expected {Expected}, got {Actual}", clientId, aud);
  29. return null;
  30. }
  31. // 이메일 인증 여부 확인
  32. var emailVerified = payload.GetProperty("email_verified").GetString();
  33. if (emailVerified != "true")
  34. {
  35. logger.LogWarning("Google token email not verified");
  36. return null;
  37. }
  38. var email = payload.GetProperty("email").GetString()!;
  39. var sub = payload.GetProperty("sub").GetString()!;
  40. var name = payload.TryGetProperty("name", out var nameProp) ? nameProp.GetString() : null;
  41. var picture = payload.TryGetProperty("picture", out var picProp) ? picProp.GetString() : null;
  42. return new GoogleUserInfo(sub, email, name, picture);
  43. }
  44. catch (Exception ex)
  45. {
  46. logger.LogError(ex, "Google token validation error");
  47. return null;
  48. }
  49. }
  50. }