본문 바로가기

Programming/php

[php] NICE API 통합형 본인확인 서비스 연동하기

나이스에서 이번에 새로 도입한 통합형 본인확인 서비스.. 매뉴얼 겁나 불친절^^

자바만 프로그램 언어인가봄.ㅎㅎㅎ예시코드 자바로 딸랑 던져주고 문의하니까 답변도 겁나 늦고~

당당히 너네 쓰는 언어 난 모르겠고 우리꺼 보고 잘 적용해서 써~ 라는 말을 좋게 포장한 답변을 들었다.

불행중에 다행인건 내가 짠 코드 통째로 메일로 보내서 어디를 고쳐야되냐고 물었더니 몇군데 집어줘서 성공했다ㅋㅋ

 

사이트 접속해서 개발가이드 파일을 다운받으면 엑셀로 된 매뉴얼 파일을 확인 할 수 있고,

설명서를 여얼심히 읽어보면 대충 흐름은 파악 할 수 있다.

 

큰 흐름은,

1. 최초 1회 기관인증토큰을 발급받는다. (반영구적 사용가능)

2. 발급받은 기관인증토큰으로 나이스 본인확인을 호출하기 위한 암호화토큰을 발급받는다.

  (본인확인을 호출할때마다 발급. 유효기간있음.)

3. 발급된 암호화토큰을 이용하여 대칭키와 무결성키를 생성한다

4. 요청할 데이터(리턴url,사이트코드,팝업여부 등)을 대칭키로 암호화하고 암호화한 데이터 무결성체크 값을 생성한다.

5. 생성한 데이터를 폼에 넣고 전송! => 여기까지 잘 진행되면 본인확인 창이 뜨고 정상적으로 진행가능

6. 리턴 url을 통해 받은 암호화 데이터를 다시 복호화한다. (ㅋㅋㅋㅋㅋ)

7. 복호화 처리한 데이터를 상태에 맞게 처리해준다.

 

그냥 휴대폰 본인확인 보다 겁나겁나 귀찮고 회원사에서 데이터를 직접 암호화/복호화 처리까지 해야한다니 처음에는 좀 당황스러웠다 ㅋㅋㅋ

 

1. 최초 1회 기관인증토큰을 발급

NICE_CLIENT_ID = 사이트에 접속해 확인가능한 클라이언트아이디
NICE_CLIENT_SEC = 사이트에 접속해 확인가능한 시크릿키값
function get_nice_og_token(){
    $url = 'https://svc.niceapi.co.kr:22001/digital/niceid/oauth/oauth/token';
    $auth = base64_encode(NICE_CLIENT_ID.":".NICE_CLIENT_SEC);
    $header = array(
        'Content-Type: application/x-www-form-urlencoded;charset=utf-8',
        'Authorization: Basic '.$auth
    );

    $ch = curl_init();
    curl_setopt_array($ch, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_POSTFIELDS => 'scope=default&grant_type=client_credentials',
        CURLOPT_HTTPHEADER => $header,
    ));

    $rtn = curl_exec($ch);
    curl_close($ch);

    if ($rtn === FALSE) {
        error_log('Curl failed');
        die('Curl failed: ' . curl_error($ch));
    }
    curl_close($ch);
    $arr_tmp = json_decode($rtn, true);

    return $arr_tmp['dataBody']['access_token'];
}

2. 암호화토큰 발급 ~ 5. 폼 전송

NICE_TOKEN = 1번에서 받은 기관토큰
NICE_PT_CODE = 사이트에서 확인 가능한 가입상품코드
function get_nice_crypto_token(){
    $url = 'https://svc.niceapi.co.kr:22001/digital/niceid/api/v1.0/common/crypto/token';
    $auth = base64_encode(NICE_TOKEN.":".time().":".NICE_CLIENT_ID);
    $header = array(
        'Content-Type: application/json',
        'Authorization: bearer '.$auth,
        'client_id:'.NICE_CLIENT_ID,
        'ProductID:'.NICE_PT_CODE
    );
    $req_dtim = date("YmdHis");
    $req_no = substr("pc".strtoupper(md5(mt_rand())), 0, 12);
    $post_in = array(
        "req_dtim" => $req_dtim,
        "req_no" => $req_no,
        "enc_mode" => "1"
    );
    $post = array(
        "dataBody"=>$post_in
    );
    $post_en = json_encode($post);

    $ch = curl_init();
    curl_setopt_array($ch, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_POSTFIELDS => $post_en,
        CURLOPT_HTTPHEADER => $header,
    ));

    $rtn = curl_exec($ch);
    curl_close($ch);

    if ($rtn === FALSE) {
        error_log('Curl failed');
        die('Curl failed: ' . curl_error($ch));
    }
    curl_close($ch);
    $res = json_decode($rtn, true);
    // ex.
    // [dataBody] => Array (
    // [rsp_cd] => P000
    // [result_cd] => 0000
    // [site_code] => Q....Q=
    // [token_version_id] => 2022.....A0B1A
    // [token_val] => uhzU.....2ypRhE=
    // [period] => 3600 ) )
    $res_cert = $res['dataBody'];
    //대칭키를 생성한다
    $_key = trim($req_dtim).trim($req_no).trim($res_cert['token_val']);
    $_key_hash = base64_encode(hash('sha256',$_key, true));
    $key = substr($_key_hash,0, 16);
    $iv = substr($_key_hash,-16);
    //무결성키를 생성한다
    $hmac_key = substr($_key_hash, 0, 32);
    //키값을 세션에 담아준다(결과데이터 복호화를 위함)
    $_SESSION['_nice_key'] = $key;
    $_SESSION['_nice_iv'] = $iv;

    //요청데이터들 암호화처리시작
    //receivedata=리턴페이지에 전달할 변수나 내용들
    $_data = array(
        "requestno" => $req_no,
        "returnurl" => "https://".$_SERVER['HTTP_HOST']."/리턴url주소.php",
        "sitecode" => $res_cert['site_code'],
        "methodtype" => 'post',
        "popupyn" => 'N',
        "receivedata" => "전달받고싶은내용"
    );
    $data = json_encode($_data, JSON_UNESCAPED_SLASHES);
    $enc_data = base64_encode(openssl_encrypt($data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv));
    //hmac 무결성체크값(intigrety_value) 생성하기
    $hmac = hash_hmac("sha256", $enc_data, $hmac_key, true);
    $intigrety_value = base64_encode($hmac);

    //form 전송할 항목
    $rtn = array(
        "token_version_id" => $res_cert['token_version_id'],
        "enc_data" => $enc_data,
        "integrity_value" => $intigrety_value,
    );

    return $rtn;
}

====> html page

<form name="form_chk" id="form_chk" method="get" action="https://nice.checkplus.co.kr/CheckPlusSafeModel/checkplus.cb">
    <input type="hidden" id="m" name="m" value="service" />
    <input type="hidden" id="token_version_id" name="token_version_id" value="<?=$rtn['token_version_id']?>" />
    <input type="hidden" id="enc_data" name="enc_data" value="<?=$rtn['enc_data']?>" />
    <input type="hidden" id="integrity_value" name="integrity_value" value="<?=$rtn['integrity_value']?>" />
    <a href="javascript:fnSubmit();"> CheckPlus 안심본인인증 Click</a>
</form>
<script language='javascript'>
    function fnSubmit(){
        document.form_chk.submit();
    }
</script>

6. 리턴 url을 통해 받은 암호화 데이터를 다시 복호화 ~ 7. 복호화 처리한 데이터를 상태에 맞게 처리

function get_decrypt_nice_data($res_enc_data, $_nice_key, $_nice_iv){
    //전송된 결과값 디코딩
    //res ex.
    //Array( [token_version_id] => 2022....DC568 [enc_data] => 8Pj1MdQ/AFcT++S/....xKUONYPAk4/Gu4zVf3nAmzp+ysU/8= [integrity_value] => ffC8DPtC3Kyp/+K.....Vi+JaV1IEc= )
    $_enc_data = base64_decode($res_enc_data); //methodtype post로 설정해서 보냈는데도 get으로 결과값 전달됨..
    //디코딩한 결과데이터 복호화처리 => charset 맞춰주기 => 배열로 디코딩
    $enc_data = openssl_decrypt($_enc_data, 'AES-128-CBC', $_nice_key, OPENSSL_RAW_DATA, $_nice_iv);
    $enc_data = iconv("euc-kr", "utf-8",$enc_data);
    $res_data = json_decode($enc_data, true);
    //res ex.
    //Array([authtype] => M [nationalinfo] => 0 [responseno] => string [resultcode] => 0000 [enctime] => int
    // 		[requestno] => string [mobileno] => 01012345678 [sitecode] => Qlc5NDQ= [di] => MC0G........7tbxcl0= [mobileco] => int
    // 		[name] => ㅅㅎㅅ [receivedata] => 전달내용 [birthdate] => 19991111 [gender] => int [utf8_name] => %EC%.......8%98)

    return $res_data;
}

$res_data = get_decrypt_nice_data($_REQUEST['enc_data'], $_SESSION['_nice_key'], $_SESSION['_nice_iv']);

=>$res_data 배열로 알맞는 처리

 

하고보면 간단한데 적용하기엔 과정이 많았다.ㅠㅠㅎㅎ