feat: 프론트 인증 연동 (소셜 로그인 + Bearer 세션)

- 로그인 화면: 구글(GIS) 버튼 + 애플 버튼 + 개발용 로그인(local)
- 인증 스토어(Pinia): 토큰 복구/로그인/로그아웃, 회원 티어를 광고·매칭 제어에 반영
- HTTP 클라이언트: Authorization Bearer 자동 첨부, 401 시 토큰 폐기 후 로그인 이동
- 라우터 가드: 미로그인 시 보호 경로 → /login (소셜 로그인 전용 앱)
- 헤더 회원 메뉴/로그아웃, 체크인 주체를 로그인 회원으로 전환
- 토큰 localStorage 저장(웹/Capacitor 공용)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
sb
2026-07-11 08:35:00 +09:00
parent f089ba2dfe
commit 0c538e0658
10 changed files with 352 additions and 9 deletions
+61
View File
@@ -0,0 +1,61 @@
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { authApi, type LoginResponse, type Member } from '@/api/auth'
import { tokenStore } from '@/lib/token'
import { useSubscriptionStore } from '@/stores/subscription'
export const useAuthStore = defineStore('auth', () => {
const member = ref<Member | null>(null)
const isAuthenticated = computed(() => member.value !== null)
/** 앱 시작 시 저장된 토큰으로 세션 복구. 실패 시 토큰 폐기. */
async function init(): Promise<void> {
if (!tokenStore.get()) return
try {
member.value = await authApi.me()
syncTier()
} catch {
tokenStore.clear()
member.value = null
}
}
function apply(res: LoginResponse): void {
tokenStore.set(res.token)
member.value = res.member
syncTier()
}
async function loginGoogle(idToken: string, rememberMe = true): Promise<void> {
apply(await authApi.google(idToken, rememberMe))
}
async function loginApple(identityToken: string, name: string | null, rememberMe = true): Promise<void> {
apply(await authApi.apple(identityToken, name, rememberMe))
}
/** 개발용: 시드된 세션 토큰으로 바로 로그인 (local 환경 검증용). */
async function devLogin(token: string): Promise<void> {
tokenStore.set(token)
member.value = await authApi.me()
syncTier()
}
async function logout(): Promise<void> {
try {
await authApi.logout()
} finally {
tokenStore.clear()
member.value = null
}
}
/** 회원의 실제 구독 티어를 광고/매칭 제어 스토어에 반영. */
function syncTier(): void {
if (member.value) {
useSubscriptionStore().setTier(member.value.subscriptionTier)
}
}
return { member, isAuthenticated, init, apply, loginGoogle, loginApple, devLogin, logout }
})