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
복사