NICE 본인인증 휴대폰본인인증

5o_hyun·2025년 4월 15일
0
post-thumbnail

✅ 전체 흐름 요약

프론트에서 버튼 클릭 → 백엔드로 요청 (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를 만들고 → 프론트에 넘겨줘야 한다.

✅ 과정

1) 나이스 인증창 폼,버튼 만들기

{/* 나이스인증창 */}
      <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>

2) 백엔드 api 호출함수(암호화토큰을 발급) 만들기

나는 /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인증창안에서 회원정보가입창이열림)

3) 프론트에서 나이스 인증창 열기

원래 코드로 돌아와서 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();
    }
  };

4) 인증완료후 가상의페이지로 redirect

지금까지 한 로직을 실행하면 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>;
}

5) 원래창에서 인증완료후 로직 실행

이제 인증된값이 원래페이지에 제대로 도착했을것이다. 그럼 인증완료후 하고싶었던 로직을 처리해준다.
// 인증완료후 하고싶은 로직 부분에, 반환된인증값 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 을 전달해주고, 팝업을 닫는다.
➏ 부모페이지(원래페이지)에서 인증된값이 주어진다.
➐ 이후 해당 인증값으로 원하는 로직을 처리한다.

profile
학생 점심 좀 차려

0개의 댓글