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:
@@ -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 }
|
||||
})
|
||||
Reference in New Issue
Block a user