fix. useTokenValidation 수정

This commit is contained in:
clkim
2025-11-04 21:13:35 +09:00
parent 80e464902c
commit e76ac480b7
7 changed files with 147 additions and 76 deletions

View File

@@ -69,7 +69,7 @@ const handleClick = () => {
validateLauncher()
return
}
if (props.platform === 'stove') {
if (props.platform === 'stove' && !isDuplication.value) {
const stoveClientDownloadUrl = runtimeConfig.public.stoveClientDownloadUrl
location.href = stoveClientDownloadUrl
return

View File

@@ -14,6 +14,8 @@ const props = withDefaults(defineProps<props>(), {
const emit = defineEmits(['confirmButtonEvent'])
const { tm } = useI18n()
const isOpen = defineModel<boolean>('isOpen', { default: false })
const setButtonEvent = (event?: () => void | void) => {
@@ -49,7 +51,7 @@ const handleOutsideClick = () => {
<AtomsButtonVariant
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || '확인' }}
{{ props.confirmButtonText || tm('Text_Confirm') }}
</AtomsButtonVariant>
</div>
</div>

View File

@@ -15,6 +15,8 @@ const props = withDefaults(defineProps<props>(), {
const emit = defineEmits(['cancelButtonEvent', 'confirmButtonEvent'])
const { tm } = useI18n()
const isOpen = defineModel<boolean>('isOpen', { default: false })
const setButtonEvent = (event?: () => void) => {
@@ -51,12 +53,12 @@ const handleOutsideClick = () => {
variant="outlined"
@click="setButtonEvent(() => emit('cancelButtonEvent'))"
>
{{ props.cancelButtonText || '취소' }}
{{ props.cancelButtonText || tm('Text_Cancel') }}
</AtomsButtonVariant>
<AtomsButtonVariant
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || '확인' }}
{{ props.confirmButtonText || tm('Text_Confirm') }}
</AtomsButtonVariant>
</div>
</div>

View File

@@ -1,5 +1,4 @@
import { useTokenValidation } from '#layers/composables/useTokenValidation'
import { csrGoStoveLogin } from '#layers/utils/stoveUtil'
interface ReqCheckSpec {
schemeFormat: string
@@ -8,8 +7,8 @@ interface ReqCheckSpec {
locale: string
}
export const useCheckPCSpec = (tm: Function) => {
const { isTokenValid, validateToken } = useTokenValidation()
export const useCheckPCSpec = (tm: (key: string) => string) => {
const { handleTokenValidation } = useTokenValidation()
// Store
const modalStore = useModalStore()
@@ -17,22 +16,6 @@ export const useCheckPCSpec = (tm: Function) => {
const isButtonDisabled = ref(false) // 버튼 비활성화 여부
/**
* STOVE 미로그인 상태일 경우 로그인 모달을 표시합니다.
* 케이스에 따라 모달 내용을 변경할 수 있습니다.
* @param content<string> 모달 내용(로그인 안내 메시지)
*/
const showLoginModal = (content: string) => {
handleOpenConfirm({
contentText: content,
confirmButtonText: tm('Download_Text_StoveLogin'),
modalName: 'modal-login',
confirmButtonEvent: () => {
csrGoStoveLogin()
},
})
}
/**
* PC사양 프로그램이 미설치일 경우 설치 안내 모달을 표시합니다.
* @param {string} setupUrl 설치 프로그램 URL
@@ -165,11 +148,11 @@ export const useCheckPCSpec = (tm: Function) => {
*/
const checkPCSpec = async (req: ReqCheckSpec) => {
const accessToken = useCookie('SUAT')
await validateToken(accessToken.value || '')
const validateTokenResult = await handleTokenValidation(
accessToken.value || ''
)
// 로그인 상태 아닐 경우
if (!isTokenValid.value) {
showLoginModal(tm('Download_Alert_StoveLogin'))
if (validateTokenResult === false) {
return
}

View File

@@ -3,26 +3,15 @@ import { useTokenValidation } from '#layers/composables/useTokenValidation'
import { csrGoStoveLogin } from '#layers/utils/stoveUtil'
export const useCheckGameStart = () => {
// const { tm } = useI18n()
const { tm } = useI18n()
const modalStore = useModalStore()
const runtimeConfig = useRuntimeConfig()
const { handleTokenValidation } = useTokenValidation()
const isProcessing = ref(false) // 연속 클릭 방지
const isShowCheckLauncher = ref(false) // 런처 실행 로딩 표시
const isShowDownloadLauncher = ref(false) // 런처 다운로드 표시
const customerService = { title: '확인', link: 'https://www.google.com' } //[TODO] 고객센터 링크
// 로그인 모달 표시
const showLoginModal = () => {
modalStore.handleOpenConfirm({
contentText: '로그인이 필요합니다.',
confirmButtonText: '스토브 로그인',
modalName: 'modal-login',
confirmButtonEvent: () => {
csrGoStoveLogin()
},
})
}
const customerService = 'https://www.google.com' //[TODO] 고객센터 링크
// 에러 처리
const errorHandler = (errorCode: number) => {
@@ -31,9 +20,8 @@ export const useCheckGameStart = () => {
break
case 40101: // 로그인 정보 확인 중 오류가 발생했습니다. 재로그인 후 다시 이용해 주세요.
modalStore.handleOpenConfirm({
contentText:
'로그인 정보 확인 중 오류가 발생했습니다. 재로그인 후 다시 이용해 주세요.',
confirmButtonText: '스토브 로그인',
contentText: tm('Alert_40101'),
confirmButtonText: tm('Text_StoveLogin'),
modalName: 'modal-login',
confirmButtonEvent: () => {
csrGoStoveLogin()
@@ -42,9 +30,8 @@ export const useCheckGameStart = () => {
break
case 40103: // 로그인 정보가 만료되었습니다. 재로그인 후 다시 이용해 주세요.
modalStore.handleOpenConfirm({
contentText:
'로그인 정보가 만료되었습니다. 재로그인 후 다시 이용해 주세요.',
confirmButtonText: '스토브 로그인',
contentText: tm('Alert_40103'),
confirmButtonText: tm('Text_StoveLogin'),
modalName: 'modal-login',
confirmButtonEvent: () => {
csrGoStoveLogin()
@@ -60,12 +47,10 @@ export const useCheckGameStart = () => {
default:
// 일시적으로 오류가 발생했습니다. 잠시 후 다시 이용해 주세요. 동일한 현상이 계속 발생할 경우 고객센터로 문의해 주세요.
modalStore.handleOpenConfirm({
contentText:
'일시적으로 오류가 발생했습니다. 잠시 후 다시 이용해 주세요. 동일한 현상이 계속 발생할 경우 고객센터로 문의해 주세요.',
confirmButtonText: customerService.title,
cancelButtonText: '취소',
contentText: tm('Alert_Error'),
confirmButtonText: tm('Text_StoveLogin'),
confirmButtonEvent: () => {
window.open(customerService.link, '_blank')
window.open(customerService, '_blank')
},
})
break
@@ -110,12 +95,12 @@ export const useCheckGameStart = () => {
window.stoveJsService = window.stoveJsService || {}
// 토큰 유효성 체크
const { validateToken } = useTokenValidation()
const validateTokenResult = await validateToken(accessTokenSub.value || '')
const validateTokenResult = await handleTokenValidation(
accessTokenSub.value || ''
)
// 토큰 유효성 체크 실패 시 로그인 모달 표시
if (!validateTokenResult) {
showLoginModal()
// 토큰 유효성 체크 실패 시
if (validateTokenResult === false) {
isProcessing.value = false
return
}

View File

@@ -1,30 +1,129 @@
export function useTokenValidation() {
// Token validation error codes
const TOKEN_ERROR_CODE = {
SUCCESS: 0,
LOGIN_INFO_ERROR: 40101,
LOGIN_INFO_INVALID: 40102,
TOKEN_EXPIRED: 40103,
TOKEN_INVALID: 40104,
} as const
type TokenErrorCode = (typeof TOKEN_ERROR_CODE)[keyof typeof TOKEN_ERROR_CODE]
interface TokenValidationResponse {
code: number
}
export const useTokenValidation = () => {
const config = useRuntimeConfig()
const apiBaseUrl = `${config.public.stoveApiUrl}`
const modalStore = useModalStore()
const { tm } = useI18n()
const apiBaseUrl = config.public.stoveApiUrl
const customerServiceUrl = 'https://www.google.com' // TODO: 고객센터 링크로 변경
const isTokenValid = ref(false)
const validateToken = async (token: string) => {
try {
const result = await $fetch<{ code: number }>(
`${apiBaseUrl}/auth/v5/user_token/check`,
{
method: 'GET',
headers: {
Authorization: `bearer ${token}`,
'Content-Type': 'application/json;charset=UTF-8',
},
}
)
isTokenValid.value = result.code === 0
return isTokenValid.value
} catch (error) {
isTokenValid.value = false
// 로그인 모달 표시
const showLoginModal = (alertKey: string) => {
modalStore.handleOpenConfirm({
contentText: tm(alertKey),
confirmButtonText: tm('Text_StoveLogin'),
modalName: 'modal-login',
confirmButtonEvent: () => {
csrGoStoveLogin()
},
})
}
// 에러 모달 표시
const showErrorModal = () => {
modalStore.handleOpenConfirm({
contentText: tm('Alert_Error'),
confirmButtonText: tm('Text_StoveLogin'),
confirmButtonEvent: () => {
window.open(customerServiceUrl, '_blank')
},
})
}
// 토큰 검증 API 호출
const validateToken = async (
token: string
): Promise<TokenErrorCode | false> => {
if (!token) {
return false
}
try {
const result = (await commonFetch(
'GET',
`${apiBaseUrl}/auth/v5/user_token/check`,
{
headers: {
Authorization: `bearer ${token}`,
},
}
)) as TokenValidationResponse
isTokenValid.value = result.code === TOKEN_ERROR_CODE.SUCCESS
return result.code as TokenErrorCode
} catch (error) {
isTokenValid.value = false
if (process.env.NODE_ENV === 'development') {
console.error('[useTokenValidation] API 호출 실패:', error)
}
return false
}
}
// 토큰 검증 및 에러 처리
const handleTokenValidation = async (token: string): Promise<boolean> => {
// 토큰 없음
if (!token) {
showLoginModal('Alert_StoveLogin')
return false
}
const result = await validateToken(token)
// API 호출 실패
if (result === false) {
showErrorModal()
return false
}
// 검증 성공
if (result === TOKEN_ERROR_CODE.SUCCESS) {
return true
}
// 로그인 정보 오류
if (
result === TOKEN_ERROR_CODE.LOGIN_INFO_ERROR ||
result === TOKEN_ERROR_CODE.LOGIN_INFO_INVALID
) {
showLoginModal('Alert_40101')
return false
}
// 토큰 만료
if (
result === TOKEN_ERROR_CODE.TOKEN_EXPIRED ||
result === TOKEN_ERROR_CODE.TOKEN_INVALID
) {
showLoginModal('Alert_40103')
return false
}
// 기타 에러
showErrorModal()
return false
}
return {
isTokenValid,
validateToken,
handleTokenValidation,
}
}

View File

@@ -98,7 +98,7 @@ export interface PageDataResourceGroup {
color_code?: string
color_name?: string
}
tracking: PageDataTracking
tracking?: PageDataTracking
}
export type PageDataResourceGroups = PageDataResourceGroup[]