Explorar el Código

feat(login): 소셜 로그인 버튼 노출을 Admin on/off 설정에 연동

- 로그인 페이지가 config.external.{naver,kakao,google}LoginEnabled 로 각 provider 버튼 노출 게이트
  (값 없으면 노출 = fail-open, 백엔드가 최종 게이트)
- types/config ExternalApiForm + configProvider DEFAULT_CONFIG 에 3개 플래그(기본 true) 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KIM-JINO5 hace 1 semana
padre
commit
d80c865ec2
Se han modificado 3 ficheros con 51 adiciones y 29 borrados
  1. 43 28
      app/(auth)/login/page.tsx
  2. 4 1
      contexts/configProvider.tsx
  3. 4 0
      types/config.ts

+ 43 - 28
app/(auth)/login/page.tsx

@@ -11,10 +11,16 @@ import { fetchApi } from '@/lib/utils/client';
 import { LoginRequest } from '@/types/request/auth';
 import { LoginResponse } from '@/types/response/auth';
 import useAuth from '@/hooks/useAuth';
+import { useConfigContext } from '@/contexts/configProvider';
 
 export default function Page()
 {
     const { login } = useAuth();
+    const config = useConfigContext();
+    // 소셜 로그인 on/off (Admin /Config/External) — 값이 없으면(구버전 config) 노출(fail-open), 백엔드가 최종 게이트
+    const naverEnabled = config?.external?.naverLoginEnabled !== false;
+    const kakaoEnabled = config?.external?.kakaoLoginEnabled !== false;
+    const googleEnabled = config?.external?.googleLoginEnabled !== false;
     const searchParams = useSearchParams();
     const [error, setError] = useState<string>('');
     const [loading, setLoading] = useState<boolean>(false);
@@ -129,36 +135,45 @@ export default function Page()
 							{loading ? "로그인 중..." : "로그인"}
 						</button>
 
-                        <div ref={googleBtnRef} className='w-full mt-2 pb-1'>
-                            {googleBtnWidth > 0 && (
-                                <GoogleLogin
-                                    onSuccess={handleGoogleLogin}
-                                    onError={handleGoogleLoginFailed}
-                                    width={googleBtnWidth}
-                                    size="large"
-                                    shape="rectangular"
-                                    context="signin"
-                                    ux_mode="redirect"
-                                    login_uri={`${window.location.origin}/login/google/callback`}
-                                    logo_alignment="center"
-                                />
-                            )}
-                        </div>
+                        {googleEnabled && (
+                            <div ref={googleBtnRef} className='w-full mt-2 pb-1'>
+                                {googleBtnWidth > 0 && (
+                                    <GoogleLogin
+                                        onSuccess={handleGoogleLogin}
+                                        onError={handleGoogleLoginFailed}
+                                        width={googleBtnWidth}
+                                        size="large"
+                                        shape="rectangular"
+                                        context="signin"
+                                        ux_mode="redirect"
+                                        login_uri={`${window.location.origin}/login/google/callback`}
+                                        logo_alignment="center"
+                                    />
+                                )}
+                            </div>
+                        )}
 
                         {/* Naver/Kakao 소셜 로그인 — start 라우트가 state 생성 후 각사 authorize 로 리다이렉트.
-                            route handler 라 Link prefetch 시 OAuth 시작이 실행되므로 일반 <a> 사용 */}
-                        <div className="social-login" role="group" aria-label="소셜 로그인">
-                            <a href="/login/naver/start" className="social-login__button social-login__button--naver">
-                                <span className="social-login__icon social-login__icon--naver" aria-hidden="true">N</span>
-                                <span>네이버 로그인</span>
-                            </a>
-                            <a href="/login/kakao/start" className="social-login__button social-login__button--kakao">
-                                <svg className="social-login__icon social-login__icon--kakao" viewBox="0 0 24 24" aria-hidden="true">
-                                    <path fill="currentColor" d="M12 3C6.48 3 2 6.54 2 10.9c0 2.8 1.86 5.25 4.64 6.65-.2.75-.74 2.72-.85 3.14-.13.53.2.52.41.38.17-.11 2.65-1.8 3.72-2.53.67.1 1.37.15 2.08.15 5.52 0 10-3.53 10-7.89S17.52 3 12 3z"/>
-                                </svg>
-                                <span>카카오 로그인</span>
-                            </a>
-                        </div>
+                            route handler 라 Link prefetch 시 OAuth 시작이 실행되므로 일반 <a> 사용.
+                            노출 여부는 Admin /Config/External 의 사용 체크박스(config.external.*LoginEnabled)로 제어 */}
+                        {(naverEnabled || kakaoEnabled) && (
+                            <div className="social-login" role="group" aria-label="소셜 로그인">
+                                {naverEnabled && (
+                                    <a href="/login/naver/start" className="social-login__button social-login__button--naver">
+                                        <span className="social-login__icon social-login__icon--naver" aria-hidden="true">N</span>
+                                        <span>네이버 로그인</span>
+                                    </a>
+                                )}
+                                {kakaoEnabled && (
+                                    <a href="/login/kakao/start" className="social-login__button social-login__button--kakao">
+                                        <svg className="social-login__icon social-login__icon--kakao" viewBox="0 0 24 24" aria-hidden="true">
+                                            <path fill="currentColor" d="M12 3C6.48 3 2 6.54 2 10.9c0 2.8 1.86 5.25 4.64 6.65-.2.75-.74 2.72-.85 3.14-.13.53.2.52.41.38.17-.11 2.65-1.8 3.72-2.53.67.1 1.37.15 2.08.15 5.52 0 10-3.53 10-7.89S17.52 3 12 3z"/>
+                                        </svg>
+                                        <span>카카오 로그인</span>
+                                    </a>
+                                )}
+                            </div>
+                        )}
 					</form>
                     <hr hidden/>
 				</fieldset>

+ 4 - 1
contexts/configProvider.tsx

@@ -104,7 +104,10 @@ const DEFAULT_CONFIG: Config = {
 		youTubeApiName: null,
 		googleClientId: null,
 		googleClientSecretEnc: null,
-		googleAppId: null
+		googleAppId: null,
+		naverLoginEnabled: true,
+		kakaoLoginEnabled: true,
+		googleLoginEnabled: true
 	},
 	toss: {
 		tossPayMode: null,

+ 4 - 0
types/config.ts

@@ -120,6 +120,10 @@ export interface ExternalApiForm {
 	googleClientId: string|null;
 	googleClientSecretEnc: string|null;
 	googleAppId: string|null;
+	// 소셜 로그인 on/off (Admin /Config/External) — 로그인 페이지 버튼 노출 게이트
+	naverLoginEnabled: boolean;
+	kakaoLoginEnabled: boolean;
+	googleLoginEnabled: boolean;
 }
 
 export interface TossForm {