KycCallback.cs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. using Infrastructure.Kyc.Nice;
  2. using MediatR;
  3. using Microsoft.Extensions.Options;
  4. using Web.Api.Common;
  5. namespace Web.Api.Endpoints.Developers.Profile;
  6. internal sealed class KycCallback : IEndpoint
  7. {
  8. // NICE 표준창 → return_url 콜백. NICE 가 query string 으로 web_transaction_id 전달.
  9. // 이 endpoint 는 cookie 없는 외부 호출이라 anonymous. 검증은 NICE result API 가 web_transaction_id 의 유효성을 보장.
  10. // 처리 후 Frontend 의 결과 페이지로 302 redirect.
  11. public void MapEndpoint(IEndpointRouteBuilder app)
  12. {
  13. app.MapGet("api/developers/profile/kyc/callback/{sessionToken}", async (
  14. string sessionToken,
  15. HttpContext httpContext,
  16. ISender sender,
  17. IOptions<NiceAuthOptions> options,
  18. CancellationToken ct
  19. ) => {
  20. var frontUrl = options.Value.FrontendCallbackUrl;
  21. if (string.IsNullOrWhiteSpace(frontUrl))
  22. {
  23. // Frontend URL 미설정 — 운영자 안내
  24. return Results.Problem(
  25. detail: "FrontendCallbackUrl 이 설정되지 않았습니다.",
  26. statusCode: 500);
  27. }
  28. var webTransactionId = httpContext.Request.Query["web_transaction_id"].ToString();
  29. if (string.IsNullOrEmpty(webTransactionId))
  30. {
  31. return Results.Redirect(BuildRedirect(frontUrl, ok: false, "인증이 취소되었습니다."));
  32. }
  33. var command = new Application.Features.Api.Developers.Profile.CompleteKyc.Command(sessionToken, webTransactionId);
  34. var result = await sender.Send(command, ct);
  35. return Results.Redirect(result.IsSuccess
  36. ? BuildRedirect(frontUrl, ok: true, null)
  37. : BuildRedirect(frontUrl, ok: false, result.Error.Description));
  38. })
  39. .WithTags("Developers")
  40. .AllowAnonymous();
  41. }
  42. private static string BuildRedirect(string frontUrl, bool ok, string? message)
  43. {
  44. var separator = frontUrl.Contains('?') ? '&' : '?';
  45. var ms = string.IsNullOrEmpty(message) ? string.Empty : "&message=" + Uri.EscapeDataString(message);
  46. return $"{frontUrl}{separator}ok={(ok ? 1 : 0)}{ms}";
  47. }
  48. }