프론트에서 버튼 클릭 → 백엔드로 요청 (enc_data, integrity_value 받기)
프론트가 받은 값으로 form submit → NICE 인증창 열림
사용자가 인증을 마치면 → NICE가 우리 백엔드에 결과를 POST로 전송
백엔드가 결과 디코딩 → 프론트에 인증 결과 보여줌
휴대폰 인증 버튼 누르면 → NICE 인증 창이 열리고 → 인증 후 돌아오는 흐름을 만들고 싶다
nice인증창은 단순 url로 열리는게 아니기때문에 enc_data
integrity_value
token_version_id
가 필요하다
이는 보안상 백엔드에서 만들어줘야한다. (token_version_id는 나이스가입할떄 준다고함 )
따라서 프론트에서 특정api에 요청하면 백엔드에서 해당값(enc_data
integrity_value
token_version_id
)들을 반환해줘야한다.
NICE 인증은 보안이 중요한 서비스라서,
암호화된 요청 데이터를 NICE에서 제공한 암호화 모듈로 만들어야 한다.
그런데 이 암호화 모듈은 프론트엔드(브라우저)에서는 사용할 수 없다.
그래서 반드시 백엔드에서 enc_data
를 만들고 → 프론트에 넘겨줘야 한다.
{/* 나이스인증창 */}
<form name="form" id="form" action="https://nice.checkplus.co.kr/CheckPlusSafeModel/service.cb">
<input type="hidden" id="m" name="m" value="service" />
<input type="hidden" id="token_version_id" name="token_version_id" value="" />
<input type="hidden" id="enc_data" name="enc_data" />
<input type="hidden" id="integrity_value" name="integrity_value" />
</form>
{/* 누를버튼 */}
<Button onClick={openNiceWindow}>인증창열기</Button>
나는 /lib/hooks
폴더에 useNiceAuthParams
라는 커스텀훅을 따로 만들었다.
// lib/hooks/useNiceAuthParams.ts
import client from '@lib/api/ClientApi';
import { useQuery } from '@tanstack/react-query';
const useNiceAuthParams = () =>
useQuery<any>({
queryKey: ['nice-auth'],
queryFn: () =>
client.NiceAuth_CryptoToken_GET({
returnurl: `${process.env.NEXT_PUBLIC_API_URL}/join/auth/nice-result`, // 가상의 페이지
}),
enabled: false,
});
export default useNiceAuthParams;
return url은 본인인증한후 이후 로직을 사용할 페이지로 보내주는건데, 이때 가상의 페이지/join/auth/nice-result
를 만들어서 가상의페이지에서 인증완료된값을 받고, 그대로 부모의 창에 다시 넣어줄것이다.
이렇게 안하면 nice팝업창 안에서 다음로직의 창이 열리기때문이다. (nice인증창안에서 회원정보가입창이열림)
원래 코드로 돌아와서 openNiceWindow
함수가 실행되면
백엔드에서 발급받은 enc_data
, integrity_value
, token_version_id
을 넣어 인증창을 열어준다
// 나이스 인증창
const { refetch } = useNiceAuthParams();
const openNiceWindow = async () => {
const form = document.getElementById('form') as HTMLFormElement;
const left = screen.width / 2 - 500 / 2;
const top = screen.height / 2 - 800 / 2;
const option = `status=no, menubar=no, toolbar=no, resizable=no, width=500, height=600, left=${left}, top=${top}`;
const { data } = await refetch();
if (form && data) {
const { enc_data, integrity_value, token_version_id } = data;
window.open('/join/auth/nice-result', 'nicePopup', option);
// 본인인증결과페이지경로 /join/auth/nice-result
form.target = 'nicePopup';
form.enc_data.value = enc_data;
form.token_version_id.value = token_version_id;
form.integrity_value.value = integrity_value;
form.submit();
}
};
지금까지 한 로직을 실행하면 redirect url을 가상의페이지인 /join/auth/nice-result
에 인증된값이 도착할것이다.
/join/auth/nice-result
페이지를 생성해준다. 이 페이지에서는 인증된값을 원래있던창/join/auth
에주고 팝업닫음
'use client';
import { useEffect } from 'react';
export default function NiceResultClient() {
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const enc_data = urlParams.get('enc_data') ?? '';
const integrity_value = urlParams.get('integrity_value') ?? '';
const token_version_id = urlParams.get('token_version_id') ?? '';
if (window.opener && enc_data && integrity_value && token_version_id) {
window.opener.postMessage({ niceAuthSuccess: true, enc_data, integrity_value, token_version_id }, '*');
window.close();
}
}, []);
return <p>본인인증 결과를 처리 중입니다...</p>;
}
이제 인증된값이 원래페이지에 제대로 도착했을것이다. 그럼 인증완료후 하고싶었던 로직을 처리해준다.
// 인증완료후 하고싶은 로직
부분에, 반환된인증값 enc_data
, integrity_value
, token_version_id
를 가지고 원하는 로직을 실행해준다.
// 인증완료후,
useEffect(() => {
const handleMessage = async (event: MessageEvent) => {
const { niceAuthSuccess, enc_data, integrity_value, token_version_id } = event.data || {};
if (niceAuthSuccess && enc_data && integrity_value && token_version_id) {
try {
// 인증완료후 하고싶은 로직
verifyMutation.mutate({
enc_data,
integrity_value,
token_version_id,
});
} catch (error) {
console.log('인증 확인 실패:', error);
Alert('인증 확인 실패');
}
}
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
➊ nice 인증폼 생성
➋ 암호화토큰을 요청할 api를 커스텀훅으로 뺀다.
➌ '인증하기' 버튼을누르면 위의 api를 호출하여 받은enc_data
,integrity_value
,token_version_id
값으로 팝업창을 연다.
(이렇게하면 나이스인증팝업창은 열린다.)
➍ 팝업창에서 인증완료후 가상페이지로 값을 받는다 (팝업창안에서 다음 로직창이 열리기떄문)
➎ 가상페이지에서 부모페이지(원래페이지)으로 인증값enc_data
,integrity_value
,token_version_id
을 전달해주고, 팝업을 닫는다.
➏ 부모페이지(원래페이지)에서 인증된값이 주어진다.
➐ 이후 해당 인증값으로 원하는 로직을 처리한다.