| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- using System.Text.Json;
- using Application.Abstractions.Authentication;
- using Microsoft.Extensions.Logging;
- namespace Infrastructure.Authentication;
- internal sealed class GoogleTokenValidator(
- HttpClient httpClient,
- ILogger<GoogleTokenValidator> logger
- ) : IGoogleTokenValidator
- {
- public async Task<GoogleUserInfo?> ValidateAsync(string credential, string clientId, CancellationToken ct)
- {
- try
- {
- var response = await httpClient.GetAsync(
- $"https://oauth2.googleapis.com/tokeninfo?id_token={credential}", ct
- );
- if (!response.IsSuccessStatusCode)
- {
- logger.LogWarning("Google token validation failed: {StatusCode}", response.StatusCode);
- return null;
- }
- var json = await response.Content.ReadAsStringAsync(ct);
- var payload = JsonSerializer.Deserialize<JsonElement>(json);
- // aud (audience) 검증
- var aud = payload.GetProperty("aud").GetString();
- if (aud != clientId)
- {
- logger.LogWarning("Google token aud mismatch: expected {Expected}, got {Actual}", clientId, aud);
- return null;
- }
- // 이메일 인증 여부 확인
- var emailVerified = payload.GetProperty("email_verified").GetString();
- if (emailVerified != "true")
- {
- logger.LogWarning("Google token email not verified");
- return null;
- }
- var email = payload.GetProperty("email").GetString()!;
- var sub = payload.GetProperty("sub").GetString()!;
- var name = payload.TryGetProperty("name", out var nameProp) ? nameProp.GetString() : null;
- var picture = payload.TryGetProperty("picture", out var picProp) ? picProp.GetString() : null;
- return new GoogleUserInfo(sub, email, name, picture);
- }
- catch (Exception ex)
- {
- logger.LogError(ex, "Google token validation error");
- return null;
- }
- }
- }
|