Search
🔎

PASS 기반 본인인증 구현 - feat. Spring & Vue

1. 요약

작업 중인 포스트입니다.
본 가이드에서는 Spring과 Vue를 사용하여 PASS 기반의 본인인증 프로세스를 소개합니다. 주요 흐름은 다음과 같이 3단계로 나뉩니다.

가. 인증요청

graph LR

A[클라이언트] -->|1. '본인 인증 URL 생성' API 호출| B[서버]
B -->|2. '본인 인증 URL' 반환| A
A -->|3. 본인 인증 팝업창 띄우기| A
Mermaid
복사

나. 인증결과 반환

graph LR

A[클라이언트] -->|4. 인증결과 요청| C
C[인증 서비스] -->|5. 'Return URL'로 리다이렉트 및 인증결과 반환| A
Mermaid
복사

다. 인증결과 후처리

graph LR

A[클라이언트] --> |6. 리다이렉트된 페이지에서 인증결과 추출| A
A -->|7. 인증결과 복호화 및 유효성 검사 요청| B[서버]
B -->|8. 복호화된 인증결과 응답| A
Mermaid
복사

2. Spring 기반 백엔드 구현

가. '본인 인증 URL' 생성 및 응답

1) API 설계
Endpoint: POST {{host}}/acc/v1/identities
Description: 클라이언트에서 제공하는 정보를 바탕으로 본인 인증 URL을 생성하고 반환합니다.
Request Parameters: callbackUrl, isMobile
Response: identityUrl
// 요청 예시 POST {{host}}/acc/v1/identities?callbackUrl=https://test.xxx.com:3000/signup/auth&isMobile=false Headers: Cookie: {본인 인증 정보} // 응답 예시 200 OK { "identityUrl": "..." }
JSON
복사
2) Application Service Logic
UserIdentityService 클래스: 본인 인증 URL을 생성하는 비즈니스 로직을 처리합니다.
createUrl 함수: Unique ID를 생성하여 URL을 만들기 위해 urlGenerator이라는 별도의 추상화 객체를 정의합니다.
@Service class UserIdentityService( private val urlGenerator: UrlGenerator, private val requestRepository: IdentityRequestRepository, ) { // 본인 인증 URL을 생성하는 함수 @Transactional fun createUrl(cmd: IdentityRequestUrlCommand): IdentityRequestUrlDto { // 사용자의 ID와 유니크한 키를 생성하여 저장합니다. val request = requestRepository.save(IdentityRequest(userId = cmd.userId, key = UniqueIdMaker.id())) // 저장된 요청 정보와 함께 URL을 생성합니다. val url = urlGenerator.generate(request, cmd.isMobile, cmd.callbackUrl) // 생성된 URL을 DTO 객체로 반환합니다. return IdentityRequestUrlDto(url) } }
Kotlin
복사

나. 인증결과 복호화 및 유효성 검사 처리

1) API 설계
Endpoint: POST {{host}}/acc/v1/identities/verify
Description: 암호화된 본인 인증 결과를 검증하고, 검증된 정보를 반환합니다.
Request Body: 암호화된 본인 인증 데이터
Response: 200 OK
// 요청 예시 POST {{host}}/acc/v1/identities/verify Headers: Cookie: {본인 인증 정보} Content-Type: application/json { "data": "{encrypted identity data}" } // 응답 예시 200 OK
JSON
복사
2) Application Service Logic
verify 함수: IdentityVerifier를 사용하여 암호화된 본인인증 데이터를 검증합니다.
UserIdentityFactory: 이전에 본인 인증되지 않은 사용자라면 본인 인증 정보를 저장합니다. 하지만 이미 본인 인증 정보가 저장된 사용자라면 최신 인증 정보로 기존 인증 정보를 업데이트합니다.
@Service class UserIdentityService( private val verifier: IdentityVerifier, private val repository: UserIdentityRepository, private val requestRepository: IdentityRequestRepository ) { private val factory = UserIdentityFactory() // 본인 인증 객체 팩토리 private val logger = LoggerFactory.getLogger(javaClass) // 로그 객체 // 본인 인증 데이터를 검증하는 함수 @Transactional fun verify(cmd: UserIdentityCommand): UserIdentityDto { // 인증 데이터를 검증합니다. val verified = verifier.verify(cmd.data) logger.info("verify user identity result code: ${verified.resultCode}, userId: ${cmd.userId}") // 검증 요청을 조회합니다. val request = requestRepository.get(verified.reqNum) ?: throw IllegalStateException("유효하지 않은 '본인 인증결과'입니다") if (request.userId != cmd.userId) throw IllegalStateException("다른 사용자의 '본인 인증결과'입니다") // 새로운 본인 인증 정보를 생성합니다. val newIdentity = factory.create(cmd.userId, data = verified) // 기존 본인 인증 정보를 조회합니다. val oldIdentity = repository.get(cmd.userId) if (oldIdentity != null) { // 기존 정보가 있으면 업데이트 합니다. oldIdentity.replace(newIdentity.profile) return UserIdentityDto(oldIdentity.phoneNumber) } // 새로운 본인 인증 정보를 저장하고 반환합니다. repository.save(newIdentity) return UserIdentityDto(newIdentity.phoneNumber) } }
Kotlin
복사

3. Vue 기반 프런트엔드 구현

가. '본인 인증 URL 생성' 처리

1) 인증 팝업 스크립트
authIdentity 함수를 호출하여 인증 URL을 가져오고, 해당 URL을 사용하여 본인 인증 팝업창을 띄웁니다.
// IdentityView.vue <script setup> async function authIdentity() { const url = await identityUrl() // 인증 URL을 가져옵니다. // 본인 인증 팝업창을 띄웁니다. window.open( url, 'DRMOKWindow', 'width=425,height=550,scrollbars=no,toolbar=no,location=no,directories=no,status=no' ) } </script>
JavaScript
복사
2) API 호출 스크립트
identityUrl 함수는 서버에서 본인 인증 URL을 가져오는 API 호출을 수행합니다.
async function identityUrl(isMobile, callbackUrl) { try { return await useAxios( `/identities?isMobile=${isMobile}&callbackUrl=${callbackUrl}`, { method: 'POST' }, apiClient ) } catch (error) { console.error('failed to create url', error) throw error } }
JavaScript
복사

나. ‘인증결과 복호화 및 유효성 검사’ 처리

1) 메시지 핸들러 스크립트
해당 호스트가 허용된 출처인지 확인한 후, 받아온 본인 인증 결과를 백엔드 서버로 전달합니다.
// IdentityRedirectionView.vue <script setup> import { useRoute } from 'vue-router' import { onMounted } from 'vue' const route = useRoute() onMounted(() => { const priinfo = route.query.priinfo if (priinfo) { window.opener.identificationReceived(priinfo) window.close() } }) </script>
JavaScript
복사
// IdentityView.vue <script setup> async function identificationReceived(priinfo) { userStore.userIdentity(priinfo) } onMounted(() => { window.identificationReceived = (data) => { identificationReceived(data) } }) onUnmounted(() => { delete window.identificationReceived }) </script>
JavaScript
복사
// userStore.js export const useUserStore = defineStore('userStore', () => { const currentUser = useStorage('currentUser', {}) async function userIdentity(encoded) { const { data } = await authApi.verifyUser(encoded) currentUser.value.phoneNumber = data.value.phoneNumber } return { userIdentity } })
JavaScript
복사
2) API 호출 스크립트
verifyIdentity 함수는 백엔드 서버에서 본인 인증 결과의 복호화 및 유효성 검사를 수행하는 API 호출을 합니다.
async function verifyIdentity(encrypted) { try { return await useAxios( '/identities/verify', { method: 'POST', data: { data: encrypted } }, apiClient ) } catch (error) { console.error('failed to verify identity', encrypted, error) throw error } }
JavaScript
복사