| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- using Application.Abstractions.Authentication;
- using Application.Abstractions.Messaging;
- using SharedKernel;
- using SharedKernel.Results;
- using Microsoft.Extensions.Options;
- namespace Application.Features.Api.Auth.SocialAuthorizeUrl;
- internal sealed class Handler(
- IEnumerable<ISocialAuthProvider> socialProviders,
- IOptions<AppSettings> options
- ) : IQueryHandler<Query, Result<Response>> {
- private readonly AppSettings.OAuthSection _oauth = options.Value.OAuth;
- public Task<Result<Response>> Handle(Query request, CancellationToken ct)
- {
- var providerName = request.Provider?.Trim().ToLowerInvariant() switch
- {
- "naver" => "Naver",
- "kakao" => "Kakao",
- _ => null
- };
- if (providerName is null)
- {
- return Task.FromResult(Result.Failure<Response>(Error.Problem("Auth.UnsupportedProvider", "지원하지 않는 소셜 로그인입니다.")));
- }
- // 네이버는 스펙상 필수, 카카오도 CSRF 방어 위해 항상 요구 (d5 §③)
- if (string.IsNullOrWhiteSpace(request.State))
- {
- return Task.FromResult(Result.Failure<Response>(Error.Problem("Auth.StateRequired", "state 값이 필요합니다.")));
- }
- var oauthConfig = providerName == "Naver" ? _oauth.Naver : _oauth.Kakao;
- if (string.IsNullOrWhiteSpace(oauthConfig.ClientId))
- {
- return Task.FromResult(Result.Failure<Response>(Error.Problem("Auth.SocialNotConfigured", $"{providerName} 로그인이 설정되지 않았습니다.")));
- }
- var redirectUri = string.IsNullOrWhiteSpace(request.RedirectUri) ? oauthConfig.RedirectUri : request.RedirectUri;
- if (string.IsNullOrWhiteSpace(redirectUri))
- {
- return Task.FromResult(Result.Failure<Response>(Error.Problem("Auth.RedirectUriRequired", "Redirect URI 가 필요합니다.")));
- }
- var provider = socialProviders.FirstOrDefault(c => c.Provider == providerName);
- if (provider is null)
- {
- return Task.FromResult(Result.Failure<Response>(Error.Problem("Auth.UnsupportedProvider", "지원하지 않는 소셜 로그인입니다.")));
- }
- var url = provider.GetAuthorizationUrl(oauthConfig.ClientId, redirectUri, request.State);
- return Task.FromResult(Result.Success(new Response(providerName, url)));
- }
- }
|