-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/sw 65 - 세션 기반 인증에서 JWT 기반 인증 전환 #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
49aad74
5c7ad55
f3386b3
9e592e6
46fc9e3
8544adb
2cb1273
e71bc18
8d50921
bcd182c
7a18ae0
94b67ad
5afa10b
c968254
c8d1dd7
f24f4f3
9d6f62b
a565c46
98bb9c0
b4f15f4
0f18403
fbbe02c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,16 +26,19 @@ repositories { | |
|
|
||
| dependencies { | ||
| implementation 'org.springframework.boot:spring-boot-starter-security' | ||
| implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' | ||
| implementation 'org.springframework.boot:spring-boot-starter-web' | ||
| implementation 'org.springframework.boot:spring-boot-starter-aop' | ||
| implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||
| implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' | ||
| implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' | ||
| implementation 'org.springframework.boot:spring-boot-starter-validation' | ||
|
Comment on lines
28
to
33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This dependency block removes Thymeleaf, but the app still has MVC controllers that return view names (for example Useful? React with 👍 / 👎. |
||
| implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' | ||
| implementation 'me.paulschwarz:spring-dotenv:4.0.0' | ||
| implementation 'org.jsoup:jsoup:1.17.2' | ||
|
|
||
| // JWT | ||
| implementation 'io.jsonwebtoken:jjwt-api:0.12.6' | ||
| runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6' | ||
| runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6' | ||
| implementation platform('org.springframework.ai:spring-ai-bom:1.1.2') | ||
| implementation 'org.springframework.ai:spring-ai-starter-model-openai' | ||
| implementation 'org.springframework.ai:spring-ai-starter-model-google-genai' | ||
|
|
||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| "use client"; | ||
|
|
||
| import { useEffect, useRef } from 'react'; | ||
| import { useRouter } from 'next/navigation'; | ||
| import { useAuthStore } from '@/lib/store/authStore'; | ||
|
|
||
| /** | ||
| * OAuth 로그인 완료 후 백엔드가 리디렉션하는 콜백 페이지 | ||
| * - 마운트 시 initialize()를 직접 호출하여 토큰 갱신 및 상태 초기화 진행 (authStore 내부에서 중복 호출 방지) | ||
| * - initialize()는 내부적으로 한 번만 실행되도록 싱글톤(Promise) 처리되어 있어 안전함 | ||
| */ | ||
|
Comment on lines
+7
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 주석과 실제 코드 동작이 불일치합니다. Line 9의 주석에서 "initialize()는 AuthProvider가 단독 호출"이라고 설명하지만, 실제로는 Line 23에서 📝 주석 수정 제안 /**
* OAuth 로그인 완료 후 백엔드가 리디렉션하는 콜백 페이지
- * - initialize()는 AuthProvider가 단독 호출 — 여기서는 결과만 구독
+ * - 마운트 시 initialize() 호출 (authStore 내부에서 중복 호출 방지)
* - 초기화 완료 후 인증 성공 여부에 따라 분기
*/🤖 Prompt for AI Agents |
||
| export default function AuthCallbackPage() { | ||
| const router = useRouter(); | ||
| const initialize = useAuthStore((s) => s.initialize); | ||
| const isInitializing = useAuthStore((s) => s.isInitializing); | ||
| const isAuthenticated = useAuthStore((s) => s.isAuthenticated); | ||
| const initialized = useRef(false); | ||
|
|
||
| // 컴포넌트 마운트 시 초기화 실행 | ||
| // - authStore.initialize() 내부에서 이미 진행 중인 Promise가 있다면 재사용하므로 안전함 | ||
| useEffect(() => { | ||
| if (!initialized.current) { | ||
| initialize(); | ||
| initialized.current = true; | ||
| } | ||
| }, [initialize]); | ||
|
|
||
| useEffect(() => { | ||
| // 초기화가 끝날 때까지 대기 | ||
| if (isInitializing) return; | ||
|
|
||
| // 인증 성공 여부에 따라 페이지 이동 | ||
| router.replace(isAuthenticated ? '/my-links' : '/login'); | ||
| }, [isInitializing, isAuthenticated, router]); | ||
|
|
||
| return ( | ||
| <div className="flex min-h-screen items-center justify-center"> | ||
| <div className="flex flex-col items-center gap-3"> | ||
| <div className="h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent" /> | ||
| <p className="text-sm text-text-sub">로그인 처리 중...</p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| import React from "react"; | ||
| import NextLink from "next/link"; | ||
| import { Input } from "@/components/ui/input"; | ||
| import { buildBackendUrl } from "@/lib/config/backend"; | ||
|
|
||
| export default function LoginPage() { | ||
| return ( | ||
|
|
@@ -137,7 +138,8 @@ export default function LoginPage() { | |
| </div> | ||
|
|
||
| {/* Google Sign In - Purple Gradient Background */} | ||
| <button type="button" className="group relative mb-6 flex h-11 w-full items-center justify-center gap-3 rounded-lg border-t border-white/20 bg-[linear-gradient(135deg,#6d28d9,#8b5cf6)] text-white shadow-md transition-all hover:brightness-110 hover:shadow-primary/25"> | ||
| {/* 소셜 로그인 시작도 백엔드 직통으로 보내야 OAuth 콜백과 쿠키 발급 주체가 일관된다. */} | ||
| <button type="button" onClick={() => { window.location.href = buildBackendUrl('/oauth2/authorization/google'); }} className="group relative mb-6 flex h-11 w-full items-center justify-center gap-3 rounded-lg border-t border-white/20 bg-[linear-gradient(135deg,#6d28d9,#8b5cf6)] text-white shadow-md transition-all hover:brightness-110 hover:shadow-primary/25"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The login button always navigates to Useful? React with 👍 / 👎. |
||
| <div className="flex h-6 w-6 items-center justify-center rounded-full bg-white p-1"> | ||
| <svg className="h-full w-full" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | ||
| <title>Google Logo</title> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
임시 파일 ignore 범위를 루트로 고정하는 편이 안전합니다.
status.txt/status_utf8.txt처럼 파일명만 적은 패턴은 하위 디렉터리의 동명 파일까지 모두 숨깁니다. 로컬 산출물만 막을 목적이면 루트 기준으로 anchoring 해 두는 편이 부작용이 적습니다.제안 수정
📝 Committable suggestion
🤖 Prompt for AI Agents