feat: 애플 로그인 네이티브 연동 (Sign in with Apple)

@capacitor-community/apple-sign-in 으로 identityToken 획득 → /api/auth/apple.
애플 버튼은 네이티브 iOS 에서만 노출, 시트 취소는 무시.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
sb
2026-07-11 10:41:29 +09:00
parent acc21b4ac7
commit d4fd4a67e2
4 changed files with 84 additions and 10 deletions
+21 -10
View File
@@ -15,8 +15,9 @@
{{ googleError }}
</div>
<!-- 애플 로그인 -->
<!-- 애플 로그인 (네이티브 iOS 전용) -->
<q-btn
v-if="appleAvailable"
class="full-width q-py-sm"
color="black"
text-color="white"
@@ -56,6 +57,7 @@ import { useQuasar } from 'quasar'
import { useAuthStore } from '@/stores/auth'
import { authApi } from '@/api/auth'
import { ApiError } from '@/api/http'
import { isAppleSignInAvailable, signInWithApple } from '@/lib/appleAuth'
const router = useRouter()
const route = useRoute()
@@ -65,6 +67,7 @@ const auth = useAuthStore()
const googleBtn = ref<HTMLElement | null>(null)
const googleError = ref('')
const appleLoading = ref(false)
const appleAvailable = isAppleSignInAvailable()
const devLoading = ref(false)
const isDev = import.meta.env.DEV
@@ -117,16 +120,24 @@ function loadGsi(): Promise<void> {
}
async function onApple() {
// 네이티브(iOS)에서는 Capacitor Sign in with Apple 플러그인으로 identityToken 을 받아
// auth.loginApple(identityToken, name) 을 호출하도록 연동 예정.
appleLoading.value = true
$q.notify({
color: 'grey-8',
message: '애플 로그인은 네이티브(iOS) 플러그인 연동이 필요합니다.',
icon: 'mdi-apple',
position: 'top',
})
appleLoading.value = false
try {
const { identityToken, name } = await signInWithApple()
await auth.loginApple(identityToken, name)
redirectAfterLogin()
} catch (e) {
// 사용자가 시트를 취소한 경우는 조용히 무시.
if (isAppleCancel(e)) return
notifyError(e)
} finally {
appleLoading.value = false
}
}
/** 애플 로그인 시트 취소 판별 — 플러그인이 취소를 에러로 reject 한다. */
function isAppleCancel(e: unknown): boolean {
const msg = (e instanceof Error ? e.message : String(e)).toLowerCase()
return msg.includes('cancel') || msg.includes('1001') || msg.includes('popup_closed')
}
async function onDevLogin() {