diff options
Diffstat (limited to 'components')
| -rw-r--r-- | components/login/login-form-shi.tsx | 18 | ||||
| -rw-r--r-- | components/login/saml-login-button.tsx | 98 |
2 files changed, 116 insertions, 0 deletions
diff --git a/components/login/login-form-shi.tsx b/components/login/login-form-shi.tsx index d22e15a8..6be8d5c8 100644 --- a/components/login/login-form-shi.tsx +++ b/components/login/login-form-shi.tsx @@ -21,6 +21,7 @@ import { verifyTokenAction } from "@/lib/users/verifyToken"; import { buttonVariants } from "@/components/ui/button" import Link from "next/link" import Image from 'next/image'; // 추가: Image 컴포넌트 import +import { KnoxSSOButton } from './saml-login-button'; // SAML 로그인 버튼 import export function LoginFormSHI({ className, @@ -225,6 +226,23 @@ export function LoginFormSHI({ <Button type="submit" className="w-full" variant="samsung" disabled={isLoading}> {isLoading ? t('sending') : t('ContinueWithEmail')} </Button> + + {/* 구분선과 "Or continue with" 섹션 추가 */} + <div className="relative"> + <div className="absolute inset-0 flex items-center"> + <span className="w-full border-t"></span> + </div> + <div className="relative flex justify-center text-xs uppercase"> + <span className="bg-background px-2 text-muted-foreground"> + {t('orContinueWith')} + </span> + </div> + </div> + + {/* SAML 로그인 버튼 - 로직 분리 */} + <KnoxSSOButton /> + + {/* 언어 선택 드롭다운 */} <div className="text-center text-sm mx-auto"> <DropdownMenu> <DropdownMenuTrigger asChild> diff --git a/components/login/saml-login-button.tsx b/components/login/saml-login-button.tsx new file mode 100644 index 00000000..2f23bedf --- /dev/null +++ b/components/login/saml-login-button.tsx @@ -0,0 +1,98 @@ +'use client' + +/** + * + * SAML 2.0 기반 SSO 로그인 요청을 시작하는 버튼 컴포넌트 + * + * + */ + +import { useState } from 'react' +import { Button } from '@/components/ui/button' +import { toast } from '@/hooks/use-toast' +import { Loader2, Shield } from 'lucide-react' +import React from 'react' + +interface SAMLLoginButtonProps { + className?: string + children?: React.ReactNode + variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'samsung' + size?: 'default' | 'sm' | 'lg' | 'icon' +} + +export function SAMLLoginButton({ + className, + children = "Knox SSO로 로그인하기", + variant = "outline", + size = "default" +}: SAMLLoginButtonProps) { + const [isLoading, setIsLoading] = useState(false) + + const handleSAMLLogin = async () => { + try { + setIsLoading(true) + + // API 엔드포인트를 통해 SAML AuthnRequest URL 생성 + const response = await fetch('/api/auth/saml/authn-request', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + + if (!response.ok) { + throw new Error('Failed to create SAML AuthnRequest') + } + + const data = await response.json() + + if (!data.success || !data.loginUrl) { + throw new Error(data.error || 'Failed to get SAML login URL') + } + + console.log('SAML Login URL:', data.loginUrl) + + // IdP로 리다이렉트 + window.location.href = data.loginUrl + + } catch (error) { + console.error('SAML Login Error:', error) + toast({ + title: '로그인 오류', + description: 'SAML 로그인을 시작할 수 없습니다.', + variant: 'destructive', + }) + setIsLoading(false) + } + } + + return ( + <Button + type="button" + variant={variant} + size={size} + className={className} + onClick={handleSAMLLogin} + disabled={isLoading} + > + {isLoading ? ( + <Loader2 className="h-4 w-4 animate-spin mr-2" /> + ) : ( + <Shield className="h-4 w-4 mr-2" /> + )} + {children} + </Button> + ) +} + +// 간단한 Knox SSO 버튼 (props 없이) +export function KnoxSSOButton() { + return ( + <SAMLLoginButton + className="w-full" + variant="outline" + > + Knox SSO (STAGE 단계) + </SAMLLoginButton> + ) +} |
