# KCP 휴대폰 본인인증 연동 (iOS/AOS)

휴대폰 본인인증 모듈은 iOS/AOS 어플리케이션 내 webview를 이용하여 연동합니다.

* [iOS 매뉴얼](#ios)
* [AOS 매뉴얼](#aos)

{% hint style="info" %}
휴대폰 본인인증 모듈에 대한 가이드는 [휴대폰 본인인증](/aurora-guide/api-1/sms-authentication.md) 문서를 참고하시길 바랍니다.&#x20;
{% endhint %}

***

### iOS 매뉴얼

#### 🅐 Xcode 설정 (iOS PASS 앱 관련 스키마 등록) <a href="#f0-9f-85-90-xcode-ec-84-a4-ec-a0-95-ios-pass-ec-95-b1-ea-b4-80-eb-a0-a8-ec-8a-a4-ed-82-a4-eb-a7-88-e" id="f0-9f-85-90-xcode-ec-84-a4-ec-a0-95-ios-pass-ec-95-b1-ea-b4-80-eb-a0-a8-ec-8a-a4-ed-82-a4-eb-a7-88-e"></a>

통신사의 PASS 앱(간편본인확인 앱)이 업데이트됨에 따라 iOS에서 가맹점 앱 서비스를 제공하는 경우, iOS9부터 보안을 강화하는 목적으로 앱을 호출할 때 앱 스키마를 등록해주어야 합니다.

| 통신사 | 앱 스키마              |
| --- | ------------------ |
| SKT | tauthlink          |
| KT  | ktauthexternalcall |
| LG  | upluscorporation   |

\
\&#xNAN;**ⓐ Info.plist 파일에 LSApplicationQueriesSchemes 배열을 정의하여 앱 스키마를 등록합니다.**

* ㉠ Information Property List에 LSApplicationQueriesSchemes를 <mark style="background-color:yellow;">Array</mark> 타입으로 추가합니다.
* ㉡ LSApplicationQueriesSchemes 하위 리스트에 String 타입으로 <mark style="background-color:yellow;">Item</mark>을 추가합니다.
* ㉢ `Item` 마다 앱 스키마를 입력합니다.

<div align="left"><figure><img src="/files/AHJIaNxcwOnXZv3AfmiI" alt=""><figcaption></figcaption></figure></div>

**ⓑ KCP 휴대폰 본인인증 완료 후 key값을 넘겨받기 위해 스키마를 등록합니다.**

<figure><img src="/files/obE02dL3gJPej37VOJ0L" alt=""><figcaption></figcaption></figure>

#### 🅑 HTML form 획득 <a href="#f0-9f-85-91html-form-ed-9a-8d-eb-93-9d" id="f0-9f-85-91html-form-ed-9a-8d-eb-93-9d"></a>

KCP 휴대폰 본인인증 모듈 팝업을 출력하기 위해서 GET /kcp/id-verification을 통해 KCP로 제출할 HTML form을 요청해야 합니다.

> [GET /kcp/id-verification/form](https://docs.shopby.co.kr/?url.primaryName=auth/#/KCPCertification/get-kcp-id-verification-form)
>
> ▶ KCP 본인인증 요청하기\
> 본인 인증을 위한 form을 생성합니다.

{% hint style="info" %}
&#x20;위 API가 아닌 임의로 form을 작성할 경우, NHN커머스 샵바이 측으로 callback을 받을 수 없습니다.

반드시 위 API 응답값으로 받은 form을 사용하시길 바랍니다.
{% endhint %}

* 응답값은 text/html 형식의 html form 양식입니다.
* returnURI는 <mark style="background-color:yellow;">scheme://</mark> 형식으로 작성합니다. (예 shopbyexample://form 🅐 - ⓑ 이미지 참고)
* 해당 API 호출시 <mark style="background-color:yellow;">request header</mark>내 <mark style="background-color:yellow;">platform</mark> 정보에 반드시 iOS를 입력하셔야 PASS 앱을 위한 아래의 추가변수가 form양식에 넘어옵니다.

<mark style="color:purple;">**✓ 예시코드**</mark>

```
<input type="hidden" name="kcp_cert_pass_use" value="Y"/>
```

#### 🅒 구현하기 <a href="#f0-9f-85-92-ea-b5-ac-ed-98-84-ed-95-98-ea-b8-b0" id="f0-9f-85-92-ea-b5-ac-ed-98-84-ed-95-98-ea-b8-b0"></a>

**ⓐ WKWebview 구성**

KCP 휴대폰본인인증 모듈은 웹으로 지원되기 때문에 WKWebview로 구성해야 합니다.

{% code overflow="wrap" %}

```
wkWebView.navigationDelegate = self
wkWebView.uiDelegate = self
wkWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
```

{% endcode %}

**ⓑ webview - LoadData**

GET /kcp/id-verification호출로 전달받은 form을 webview에 로드합니다.

{% code overflow="wrap" %}

```
var htmlString = """
<html><title>KCPCert</title>
<body>\(formData)</body>  // formData 는 html form 양식입니다.
</html>
"""wkWebView.loadHTMLString(htmlString, baseURL: Bundle.main.bundleURL)
```

{% endcode %}

**ⓒ form.submit()**

webview의 <mark style="background-color:yellow;">evaluateJavaScript</mark>을 이용하여 form을 submit합니다.\
form이 submit되면 webview에서 새 창으로 KCP 휴대폰 본인인증 페이지가 노출됩니다.

{% hint style="info" %}
휴대폰 본인인증 화면은 WKWebview에서 새 창으로 열릴 수 있도록 구성해 주셔야 합니다. (ⓒ참고)

`evaluateJavaScript`는 html 폼 양식이 완전히 로드된 후( `webview didFinish`시점) 호출해 주시면 됩니다.
{% endhint %}

{% code overflow="wrap" %}

```
let injectJavaScript: String = """
// form id : form_auth
document.getElementById("form_auth").submit();
"""
var jsStr = injectJavaScript.trimmingCharacters(in: .whitespaces)
jsStr = jsStr.trimmingCharacters(in: .whitespacesAndNewlines)
jsStr = jsStr.trimmingCharacters(in: .newlines)
wkWebView.evaluateJavaScript(jsStr, completionHandler: nil)
```

{% endcode %}

**ⓓ WKWebview 구현**

WKWebview를 새 창으로 구현합니다.

아래 구현방식은 KCP 휴대폰 본인인증 연동을 위한 샘플이며, 개발 시 참고용으로 사용하시길 바랍니다.

{% code overflow="wrap" %}

```
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    let createWebView = WKWebView(frame: self.wkWebView.frame, configuration: configuration)
    createWebView.navigationDelegate = self
    createWebView.uiDelegate = self
    self.view.addSubview(createWebView)
    return createWebView
}
```

{% endcode %}

**ⓔ Key 파라미터 획득**

<mark style="background-color:yellow;">returnURI</mark>로 전달받은 <mark style="background-color:yellow;">URI</mark>를 parsing하여 <mark style="background-color:yellow;">key</mark>값을 추출합니다.\
WKWebview Delegate (WKNavigationDelegate)

{% code overflow="wrap" %}

```
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {
    var policy = WKNavigationActionPolicy.allow
    if let requestURL = navigationAction.request.url {
        if requestURL.scheme == "shopbyexample"  {
                        if let host = requestURL.host, host == "form" {
                            if let _ = requestURL.query as String? {
                                if let urlComponent = URLComponents(url: requestURL, resolvingAgainstBaseURL: true) {
                                    let queryItems = urlComponent.queryItems
                                    if let key = queryItems?.first(where: { $0.name == "key" })?.value {
                                        print("key : \(key)")
                                    }
                                }
                            }
                            policy = .allow
                            decisionHandler(policy, preferences)
                            return
                        }
                    }
                    UIApplication.shared.open(requestURL, options: [:], completionHandler: nil)
                    policy = .cancel
    }
    decisionHandler(policy, preferences)
}
```

{% endcode %}

#### 🅓 본인인증 결과 조회 <a href="#f0-9f-85-93-eb-b3-b8-ec-9d-b8-ec-9d-b8-ec-a6-9d-ea-b2-b0-ea-b3-bc-ec-a1-b0-ed-9a-8c" id="f0-9f-85-93-eb-b3-b8-ec-9d-b8-ec-9d-b8-ec-a6-9d-ea-b2-b0-ea-b3-bc-ec-a1-b0-ed-9a-8c"></a>

해당 <mark style="background-color:yellow;">key</mark>로 본인인증 인증 성공 및 실패 여부를 판단한 뒤, 화면에 성공 및 실패 결과를 전달합니다.

> [GET /kcp/id-verification/response](https://docs.shopby.co.kr/?url.primaryName=auth/#/KCPCertification/get-kcp-id-verification-response)
>
> ▶ KCP 본인인증 결과 조회하기\
> NHN KCP 본인인증 결과를 확인합니다.

#### 🅔 샘플코드(참고) <a href="#f0-9f-85-94-ec-83-98-ed-94-8c-ec-bd-94-eb-93-9c-ec-b0-b8-ea-b3-a0" id="f0-9f-85-94-ec-83-98-ed-94-8c-ec-bd-94-eb-93-9c-ec-b0-b8-ea-b3-a0"></a>

[KCPCertViewController.swift](https://nhnent.dooray.com/share/tree/WoOk8q6KT1K3MZcLSuyZsw/pages/3615381963904646601/files/3615931128094936280) 참고

***

### AOS 매뉴얼

#### 🅐 webview 세팅 <a href="#f0-9f-85-90-webview-ec-84-b8-ed-8c-85" id="f0-9f-85-90-webview-ec-84-b8-ed-8c-85"></a>

KCP 본인인증을 모바일로 사용하기 위해 webview를 세팅합니다.

{% code overflow="wrap" %}

```
binding.webView.apply {
    settings.apply {
        javaScriptEnabled = true
        javaScriptCanOpenWindowsAutomatically = true
        supportMultipleWindows()
    }
}
```

{% endcode %}

#### 🅑 HTML form 획득 <a href="#f0-9f-85-91-html-form-ed-9a-8d-eb-93-9d" id="f0-9f-85-91-html-form-ed-9a-8d-eb-93-9d"></a>

KCP 휴대폰 본인인증 모듈 팝업을 출력하기 위해서 GET /kcp/id-verification을 통해 KCP로 제출할 HTML form을 요청해야 합니다.

> [GET /kcp/id-verification/form](https://docs.shopby.co.kr/?url.primaryName=auth/#/KCPCertification/get-kcp-id-verification-form)
>
> ▶ KCP 본인인증 요청하기\
> 본인 인증을 위한 form을 생성합니다.

{% hint style="info" %}
위 API가 아닌 임의로 form을 작성할 경우, NHN커머스 샵바이 측으로 callback을 받을 수 없습니다.

반드시 위 API 응답값으로 받은 form을 사용하시길 바랍니다.
{% endhint %}

* 응답값은 text/html 형식의 html form 양식입니다.
* returnURI는 <mark style="background-color:yellow;">scheme://</mark> 형식으로 작성합니다. (예 shopbyexample://form.html)

**ⓐ webview - LoadData**

GET /kcp/id-verification을 호출하여 전달받은 form을 webview에 로드합니다.

{% code overflow="wrap" %}

```
loadDataWithBaseURL(baseUrl, apiResponseData, "text/html", "UTF-8", "")
```

{% endcode %}

**ⓑ form.submit()**

webview의 <mark style="background-color:yellow;">evaluateJavaScript</mark>을 이용하여 form을 submit합니다.\
form이 submit되면 webview에서 KCP 휴대폰 본인인증 페이지로 리다이렉트 됩니다.

{% code overflow="wrap" %}

```
binding.webView.evaluateJavascript("document.form_auth.submit()") {}
```

{% endcode %}

<mark style="background-color:yellow;">evaluateJavaScript</mark>는 html 폼 양식이 완전히 로드된 후 <mark style="background-color:yellow;">WebViewClient</mark>를 이용하여 호출할 수 있습니다.

{% code overflow="wrap" %}

```
binding.webView.apply {
    webViewClient = object : WebViewClient() {
        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            if (url?.startsWith(baseUrl) == true) {
                binding.webView.evaluateJavascript("document.form_auth.submit()") {}
            }

        }
    }
}
```

{% endcode %}

**ⓒ Key 파라미터 획득**

본인인증이 정상적으로 끝났다면, <mark style="background-color:yellow;">returnURI</mark>로 <mark style="background-color:yellow;">key</mark>값을 전달 받습니다.

```
{YOUR_RETURN_URL}?key=XXXXXXXXXX
```

<mark style="background-color:yellow;">WebViewClient</mark>의 <mark style="background-color:yellow;">shouldOverrideUrlLoading</mark>을 통해 <mark style="background-color:yellow;">key</mark>값을 추출할 수 있습니다.

{% code overflow="wrap" %}

```
binding.webView.apply {
    webViewClient = object : WebViewClient() {
        override fun shouldOverrideUrlLoading(
            view: WebView?,
            request: WebResourceRequest?
        ): Boolean {
            if (request?.url.toString().startsWith(returnUrl)) {
                val uri = Uri.parse(request?.url.toString())
                val isContainsKey = uri.queryParameterNames.contains("key") // 파라미터에 key가 포함되어있는지 확인
                if (isContainsKey) println("key = ${uri.getQueryParameter("key")}") // key 추출

                //TODO:  key 추출 이후 과정을 이 곳에서 진행하시면 됩니다.
                return isContainsKey
            }
            return super.shouldOverrideUrlLoading(view, request)
        }
    }
}
```

{% endcode %}

#### 🅓 본인인증 결과 조회 <a href="#f0-9f-85-93-eb-b3-b8-ec-9d-b8-ec-9d-b8-ec-a6-9d-ea-b2-b0-ea-b3-bc-ec-a1-b0-ed-9a-8c" id="f0-9f-85-93-eb-b3-b8-ec-9d-b8-ec-9d-b8-ec-a6-9d-ea-b2-b0-ea-b3-bc-ec-a1-b0-ed-9a-8c"></a>

해당 <mark style="background-color:yellow;">key</mark>로 본인인증 인증 성공 및 실패 여부를 판단한 뒤, 화면에 성공 및 실패 결과를 전달합니다.

> [GET /kcp/id-verification/response](https://docs.shopby.co.kr/?url.primaryName=auth/#/KCPCertification/get-kcp-id-verification-response)
>
> ▶ KCP 본인인증 결과 조회하기\
> NHN KCP 본인인증 결과를 확인합니다.

#### 🅔 샘플코드(참고) <a href="#f0-9f-85-94-ec-83-98-ed-94-8c-ec-bd-94-eb-93-9c-ec-b0-b8-ea-b3-a0" id="f0-9f-85-94-ec-83-98-ed-94-8c-ec-bd-94-eb-93-9c-ec-b0-b8-ea-b3-a0"></a>

[MainActivity.kt](https://nhnent.dooray.com/share/tree/WoOk8q6KT1K3MZcLSuyZsw/pages/3615381963904646601/files/3615929480452935780) 참고


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://workspace-help.nhn-commerce.com/aurora-guide/kcp-sms-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
