# 회원 연동 (POST)

***

## **➊ 회원 연동**

### **1-1. 개요** <a href="#id-2" id="id-2"></a>

{% hint style="info" %}
**회원 연동이란?**

자체 사용 중인 서비스의 회원 인증을 콘티플의 헬프센터에 적용하여 회원 문의를 접수하고,\
접수한 문의 내역을 다시 확인할 수 있도록 제공하는 기능입니다.
{% endhint %}

* 회원 연동은 GET 방식과 POST 방식의 두 가지 타입으로 제공합니다.
* 연동을 위해 콘티플에서 제공하는 개발 명세서에 따라 API를 개발하여 회원 연동 메뉴에 등록해주세요.

#### **(1) POST 방식**

* 연동하려는 서비스가 PC, Mobile 플랫폼에서 WEB 기반으로 제공될 경우 적합합니다.
* 서비스의 로그인 화면이 WEB URL 형태로 제공되어야 사용 가능합니다.
* 개발 명세에서 세부적으로 2가지 타입을 제공합니다. (Client-side, Sever-side)

#### **(2) GET 방식**

* WEB 기반의 로그인 화면이 없는 서비스의 경우 적합합니다.
* WEB 기반이 아닌 Native APP 서비스의 경우 적합한 연동 방식입니다.

***

### **1-2. 프로세스 (POST 방식)** <a href="#post" id="post"></a>

<figure><img src="https://2615864196-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSsOdZGrk2XR1u1MFkuK1%2Fuploads%2FohpBaV7RoWsKy5zBpIbP%2Fimage.png?alt=media&#x26;token=05c38b2b-942b-4f6e-b7df-af9aa6c6523c" alt=""><figcaption></figcaption></figure>

{% stepper %}
{% step %}
유저가 헬프센터 1:1 문의 또는 문의내역 페이지에 접속합니다.
{% endstep %}

{% step %}
SSO 회원연동 설정이 '활성화' 상태일 경우 [**로그인 상태 URL**](#id-2-5.-post-url)이 호출됩니다.

* [로그인 상태 URL](#id-2-5.-post-url)은 가이드에 따라 직접 개발해야 하며, Contiple 측으로 로그인 여부를 리턴해야합니다.
  {% endstep %}

{% step %}
유저가 로그아웃 상태일 경우 status = false로 리턴합니다.
{% endstep %}

{% step %}
이 경우 사용자 로그인을 유도하기 위해 [**로그인 URL 페이지**](#id-2-4.-post-url)로 리다이렉션 됩니다.

* 리다이렉션 시, returnUrl 파라미터가 자동 추가되며, 로그인 성공 시 1에서 사용자가 접속했던 페이지로 이동시키기 위해 해당 URL이 적용됩니다.
  {% endstep %}

{% step %}
사용자는 ID, PW를 입력하여 로그인을 시도합니다.
{% endstep %}

{% step %}
로그인 성공 시 4에서 제공했던 **returnUrl로 리다이렉션 처리**합니다.

* 프로세스 상 다시 2번 단계로 이동하여 **로그인 상태 URL**을 호출합니다.
  {% endstep %}

{% step %}
로그인 상태일 경우 status = 'true'로 리턴하고, 고객 측 서버 에서 [**원격 로그인 API**](#id-2-3.-post-api-from-server-side)를 호출하여 고객정보(이름, 이메일, 전화번호 등)를 Contiple에 전달합니다.

* 전달된 정보는 1:1 문의 접수 시 고객정보 관련 필드에 자동 입력됩니다.
  {% endstep %}

{% step %}
Contiple에서는 제공된 고객정보로 Access Token을 발급합니다.
{% endstep %}

{% step %}
고객 측 서버에서는 유저가 접속한 1:1문의/문의내역 페이지로 이동시키며 발급된 Access Token을 파라미터로 제공합니다.
{% endstep %}

{% step %}
제공된 Access Token 유효성을 확인한 후 유저 측으로 페이지가 랜더링됩니다.
{% endstep %}
{% endstepper %}

***

### **1-3. 회원연동 설정 방법** <a href="#post" id="post"></a>

#### **① 회원 연동 활성화**

* \[서비스 관리] → \[헬프센터] → \[회원 연동]으로 이동합니다.
* 회원 연동을 사용하려면 **활성화**로 설정합니다.

#### **② 비회원 문의 접수**

* <mark style="color:green;">활성화 :</mark> (고객이) 로그인하지 않은 상태에서도 문의 접수가 가능해집니다.
* <mark style="color:orange;">비활성화 :</mark> 로그인 상태에서만 문의 접수가 가능하도록 통제됩니다.

#### **③ 로그인 타입**

* POST 방식을 선택합니다.

#### **④ URL 설정**

* [**로그인 URL**](#id-2-4.-post-url) : 로그인 상태 URL 호출 후유저가 로그인 상태가 아니라면 이동할 로그인 화면 URL
* [**로그인 상태 URL** ](#id-2-5.-post-url): 헬프센터 접속 또는 페이지 이동 시, 유저 로그인 상태를 체크하는 URL
* 두 URL은 하단의 개발 명세서를 참고하여 자체 운영 중인 서비스에서 제공해야 합니다.

#### **⑤ 파라미터 설정**

* 필요에 따라 [**원격 로그인 API**](#id-2-3.-post-api-from-server-side)를 통해 Contiple로 전달되는 고객 정보를 추가할 수 있으며요청 헤더 또는 쿼리에 포함하여 전송할 수 있습니다.
* 파라미터 명칭은 원격 로그인 API를 통해 고객 측에서 전달하는 파라미터 명칭과 동일해야 합니다.

#### ⑥ 고객 정보 암호화

* [원격 로그인 API](#id-2-3.-post-api-from-server-side)를 통해 고객정보를 Contiple로 전달할 때 이름, 이메일, 전화번호 등의 데이터를 암호화하고 싶을 경우 활성화합니다.
* 활성화 시 API Key가 생성되며 [원격 로그인 API](#id-2-3.-post-api-from-server-side) 호출 시 가이드에 따라 해당 키로 암호화해서 전송해야 합니다.
* Contiple에서는 암호화된 데이터를 해당 API Key로 복호화하여 데이터를 처리하게 됩니다.

***

## **➋ 개발 명세서**

### **2-1. 인증토큰 생성**

{% hint style="info" %}
**콘티플 조직 Key**

\[전체 관리] → \[계약 서비스 현황] → 조직 정보]에서 확인할 수 있습니다.
{% endhint %}

> Token 생성 샘플은 아래와 같으며, 파라미터 순서는 반드시 아래와 일치해야 합니다.
>
> (※ Sample project > application.properties > oc.apikey= 항목에 조직 Key 저장)

```java
private String getSHA256Token(String serviceId, String usercode, String username, String email, String phone,
        String returnUrl, Long time, String apiKey) throws Exception {
    StringBuilder sb = new StringBuilder();
    // Order by follow number:
    sb.append(serviceId); // 1
    sb.append("&");
    sb.append(usercode); // 2
    sb.append("&");
    if (StringUtils.isNotBlank(username)) {
        sb.append(username); // 3
        sb.append("&");
    }
    if (StringUtils.isNotBlank(email)) {
        sb.append(email); // 4
        sb.append("&");
    }
    if (StringUtils.isNotBlank(phone)) {
        sb.append(phone); // 5
        sb.append("&");
    }
    　if (StringUtils.isNotBlank(memberno)) {
        sb.append(memberno); // 6
        sb.append("&");
    　}
    if (StringUtils.isNotBlank(returnUrl)) {
        sb.append(returnUrl); // 7
        sb.append("&");
    }
    sb.append(time); // 8

    SecretKeySpec signingKey = new SecretKeySpec(apiKey.getBytes("UTF-8"), "HmacSHA256");
    Mac mac = Mac.getInstance(signingKey.getAlgorithm());
    mac.init(signingKey);
    byte[] rawHmac = mac.doFinal(sb.toString().getBytes("UTF-8"));
    return new String(Base64.encodeBase64(rawHmac));
}

// Sample
// Use this same input, the output is : Ah9M58CQ9RFTShjFuqziQr+0MjmJxN6+bzWxMD71moo=
public static void main(String[] args) throws Exception {
    String s = getSHA256Token("yourService", "testusercode", "testUsername", "test@email.com", "123456789",
    null, 1660095873001L, "7cf2828608274a49a3f06152b2188927");
    System.out.println(s); // Output: Ah9M58CQ9RFTShjFuqziQr+0MjmJxN6+bzWxMD71moo=
}
```

***

### **2-2. POST 원격 로그인 API (From Client Side)**

**(1) 인터페이스 설명**

* URL: https\://{domain}.oc.nhncloud.com/v2/enduser/remote.json

| 인터페이스 명                           | 프로토콜  | 호출방향 | 인코딩   | 결과 형식    | 인터페이스 설명                                                                                                     |
| --------------------------------- | ----- | ---- | ----- | -------- | ------------------------------------------------------------------------------------------------------------ |
| POST 원격 로그인 API(From client side) | HTTPS | POST | UTF-8 | Redirect | 사용자 시스템에서 동적으로 form를 생성하여 브라우저에 반환하며, form은 자동으로 API에 form정보를 전달. API에서 전달된 form정보로 인증 후 성공시 로그인 Cookie 값 설정 |

{% hint style="info" %}
**사용자 시스템에서의 호출 방법은 하단 Sample project의 다음과 같은 class를 참조해주세요**

* FormLoginController.java
* Method: submitLogin
  {% endhint %}

***

**(2) 요청 파라미터 정의**

| 명칭               | 변수        | 데이터 타입       | 필수 | 설명                                                                                                                                                                                                                    |
| ---------------- | --------- | ------------ | -- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 서비스ID            | service   | Varchar(50)  | O  | 서비스 ID                                                                                                                                                                                                                |
| 유저ID             | usercode  | Varchar(50)  | O  | 유저ID，유일한 유저임을 표시                                                                                                                                                                                                      |
| 유저 명             | username  | Varchar(50)  | X  | 유저 명                                                                                                                                                                                                                  |
| 유저 이메일 주소        | email     | Varchar(100) | X  | 유저 이메일                                                                                                                                                                                                                |
| 전화번호             | phone     | Varchar(20)  | X  | 전화번호                                                                                                                                                                                                                  |
| 회원번호             | memberno  | Varchar(50)  | X  | 회원번호                                                                                                                                                                                                                  |
| 현재 시간의 timestamp | time      | Long         | O  | 호출 시간이 3분 초과 시, 타임아웃 얼럿 출력.                                                                                                                                                                                           |
| 인증 Token         | token     | Varchar      | O  | 다음 파라미터 값과 조직 Key로 산출된 SHA256(필수가 아닌 파라미터 값이 null 혹은 빈값일 경우, 암호화 문자열에 추가할 필요 없음. 주의: 문자열 중 각 값의 순서는 다음 예시에 지정된 순서와 일치해야 함.) SHA256Digest(service & usercode & username & email & phone & memberno & returnUrl & time) |
| 리턴 화면 URL        | returnUrl | Varchar      | X  | 설정 및 로그인 성공 시 해당 주소로 이동                                                                                                                                                                                               |

***

**(3) 결과 데이터**

* returnUrl 파라미터 존재 시 지정된 returnUrl로 이동
* returnUrl 파라미터가 없을 경우 문자열(SUCCESS) 반환

***

### **2-3. POST 원격 로그인 API (From Server Side)**

**(1) 인터페이스 설명**

* URL: https\://{domain}.oc.nhncloud.com/api/v2/enduser/remote.json

| 인터페이스 명                           | 프로토콜  | 호출방향 | 인코딩   | 결과 형식  | 인터페이스 설명                                          |
| --------------------------------- | ----- | ---- | ----- | ------ | ------------------------------------------------- |
| POST 원격 로그인 API(From server side) | HTTPS | POST | UTF-8 | String | 사용자가 서버에서 직접 API 호출. API 로그인 성공 후 로그인 Cookie 값 설정 |

{% hint style="info" %}
**사용자 시스템에서의 호출 방법은 하단 Sample project의 다음과 같은 class를 참조해주세요.**

* ApiLoginController.java
* Method: submitLogin
  {% endhint %}

***

#### **(2) 요청 파라미터 정의**

| 명칭               | 변수       | 데이터 타입       | 필수 | 설명                                                                                                                                                                                                        |
| ---------------- | -------- | ------------ | -- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 서비스ID            | service  | Varchar(50)  | O  | 서비스 ID                                                                                                                                                                                                    |
| 유저ID             | usercode | Varchar(50)  | O  | 유저ID, 유일한 유저임을 표시                                                                                                                                                                                         |
| 유저 명             | username | Varchar(50)  | X  | 유저 명                                                                                                                                                                                                      |
| 유저 이메일 주소        | email    | Varchar(100) | X  | 유저 이메일                                                                                                                                                                                                    |
| 전화번호             | phone    | Varchar(20)  | X  | 전화번호                                                                                                                                                                                                      |
| 회원번호             | memberno | Varchar(50)  | X  | 회원번호                                                                                                                                                                                                      |
| 현재 시간의 timestamp | time     | Long         | O  | 호출 시간이 3분 초과 시, 타임아웃 얼럿 출력.                                                                                                                                                                               |
| 인증 Token         | token    | Varchar      | O  | 다음 파라미터 값과 조직 Key로 산출된 SHA256(필수가 아닌 파라미터 값이 null 혹은 빈값일 경우, 암호화 문자열에 추가할 필요 없음. 주의: 문자열 중 각 값의 순서는 다음 예시에 지정된 순서와 일치해야 함.) SHA256Digest(service & usercode & username & email & phone & memberno & time) |

***

#### **(3) Response Data**

> 헬프센터 호출 시, 리턴된 content 값을 헬프센터 URL 파라미터 - accessToken 값으로 지정하여 콘티플에 전달합니다.
>
> * 예시: <https://yourorg.oc.nhncloud.com/yourService/hc/?accessToken=xxxxxxaccessTokenxxxxxxx>

```json
{   
  "header": {   
    "resultCode": 200,  
    "resultMessage": "",    
    "isSuccessful": true    
  },    
  "result": {   
    "content": "xxxxxxaccessTokenxxxxxxx"   
  } 
}
```

***

### **2-4. POST 로그인 URL (사용자)**

**(1) 인터페이스 설명**

* URL: 사용자 제공
* URL(개발): 사용자 제공

| 인터페이스 명           | 프로토콜  | 호출방향 | 인코딩   | 결과 형식    |
| ----------------- | ----- | ---- | ----- | -------- |
| POST 로그인 URL(사용자) | HTTPS | GET  | UTF-8 | Redirect |

> 서비스 측 로그인 URL은 아래와 같은 기능을 제공해야 합니다.
>
> * **사용자 로그아웃 상태**
>   * 로그인 화면 출력
>
>   * 계정/비밀번호로 로그인 진행
>
>   * 로그인 성공 후 cookie 생성 및 로그인 상태 기록, 로그인 상태 체크 시 사용됨
>
>   * 로그인 성공 후 Client 혹은 Server단에서 고객 정보를 Online Contact으로 전달(POST 원격 로그인 API(From client side), POST 원격 로그인 API(From server side) 참조)
> * **사용자 로그인 상태**
>   * 로그인 성공 후 Client 혹은 Server단에서 고객 정보를 Online Contact으로 전달(POST 원격 로그인 API(From client side), POST 원격 로그인 API(From server side) 참조)

> **SSO 로그인 기능**
>
> * **사용자 로그아웃 상태**
>   * ① 로그인 화면으로 이동
>
>   * ② 사용자 로그인
>
>   * ③ 서비스 측의 서버에서 사용자 로그인 처리 및 로그인 사용자 관련 쿠키 생성
>
>   * ④ POST 원격 로그인 API 호출(POST 원격 로그인 API(From client side), POST 원격 로그인 API(From server side) 참조)
> * **사용자 로그인 상태**
>   * POST 원격 로그인 API 호출(POST 원격 로그인 API(From client side), POST 원격 로그인 API(From server side) 참조)

> **POST 원격 로그인 API 호출 방법**
>
> 1. **POST 원격 로그인(From client side)**
>    1. 사용자 정보와 API Key 기준으로 로그인 token 생성
>
>    2. 사용자 정보와 token을 브라우저로 리다이렉트
>
>    3. 화면에서 Form 작성, 상세한 파라미터는 POST 원격 로그인 API(From client side) 참조
>
>    4. Form 제출출
>
>    5. POST 원격 로그인 API를 통해 사용자 정보와 token 전송
>
>    6. 로그인 성공 후 {returnUrl}로 이동
> 2. **POST 원격 로그인(From server side)**
>    1. 사용자 정보와 API Key 기준으로 로그인 token 생성
>    2. 서버에서 POST 원격 로그인 API(From server side) 호출
>    3. API 호출 파라미터(usercode, time)를 returnUrl 뒤에 추가
>       * (예시) <https://yourorg.oc.nhncloud.com/yourService/hc/ticket/list/?usercode=xxxxxx@163.com\\&time=1566531359635>
>    4. {returnUrl}로 이동

***

### **2-5. POST 로그인 상태 URL (사용자)**

#### **(1) 인터페이스 설명**

* URL: 사용자 제공

| 인터페이스 명              | 프로토콜  | 호출방향 | 인코딩   | 결과 형식 | 인터페이스 설명                                                                                       |
| -------------------- | ----- | ---- | ----- | ----- | ---------------------------------------------------------------------------------------------- |
| POST 로그인 상태 URL(사용자) | HTTPS | GET  | UTF-8 | JSON  | 사용자가 쿠키 정보를 기준으로 로그인 여부를 확인 후 JSON 형식의 데이터를 리턴. 서비스 측 Server에서 response에 Cross domain 접속 설정 필요 |

> **Cross Domain 접속 설정 방법**
>
> ```
> response.addHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
> response.addHeader("Access-Control-Allow-Credentials", "true");
> ```

{% hint style="info" %}
**사용자 시스템에서의 구현 방법은 하단 Sample project의 다음과 같은 class를 참조해주세요**

* FormLoginController.java
* Method: loginStatus
  {% endhint %}

***

#### **(2) 요청 파라미터 정의**

* 없음

***

#### **(3) 결과 데이터**

<table><thead><tr><th width="202">명칭</th><th width="118">변수</th><th width="125">데이터 타입</th><th width="73">필수</th><th>설명</th></tr></thead><tbody><tr><td>javascript function</td><td>login</td><td>Boolean</td><td>O</td><td>로그인 상태. 로그인: true, 로그아웃: false</td></tr><tr><td>유저 ID</td><td>usercode</td><td>Varchar(50)</td><td>X</td><td>유저 ID(유니크 값). 로그인 상태가 true인 경우 필수</td></tr></tbody></table>

***

#### **(4) Response Body**

```json
{
"login": "true",
"usercode":"usercodeXXX"
}

{
"login": "false",
"usercode": null
}
```

***

## **➌ 적용 예시**

### **3-1. Sample Code**

* Sample Code 다운로드

{% file src="<https://2615864196-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSsOdZGrk2XR1u1MFkuK1%2Fuploads%2Foiyl1Nwz180m3mgrx0QE%2Foc_sso_sample-20220817.zip?alt=media&token=e91a5082-60c9-40d1-ad82-34d1f2b13514>" %}

***

### **3-2. iframe 이용 예시**

**(1) iframe으로 콘티플 헬프센터를 사용자 페이지에 삽입**

* Sample Code 파일 중 'oc\_sso\_sample/src/main/resources/templates/help\_frame.ftl'을 참조해주세요.
* iframe의 이름은 반드시 id = "ocPage"로 지정해야 합니다.

```
<iframe src="https://${domain}/yourService/hc/?iframe=true" id="ocPage" frameborder="0" scrolling="no" 
      style="padding-top: 60px; box-sizing: unset; height: 100px; width: 100%"></iframe>
```

* 페이지에 viewport 설정 시 mobile/web 브라우저 모두에서 헬프센터를 사용할 수 있습니다.

```
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0">
```

***

**(2) Parent 페이지에서 콘티플 헬프센터의 높이를 확인하여 iframe의 height 조정**

* help\_frame.ftl 파일 중 javascript 코드를 참조하십시오.

```javascript
// Listener for OC content height change
window.addEventListener('message',function(event){
    // Set iframe height
    if(event.data > 0) {
    updateHeight(event.data);
    }
});

var updateHeight = function(wrapHeight) {
var iframe = window.document.getElementById('ocPage');
if(iframe != null) {
iframe.style.height = '0px'; 
var setHeight = (document.body.clientHeight > document.body.scrollHeight) ? document.body.clientHeight : document.body.scrollHeight;
var margin = 70;
setHeight = setHeight > wrapHeight ? setHeight : wrapHeight;
iframe.style.height = setHeight + margin + "px";
}
};
```

***

**(3) 사용자 시스템에서 Login 후 설정해야 할 Cookie는 사용자 페이지에서 취득**

* help\_frame.ftl 파일 중 javascript 코드를 참조하십시오.

```javascript
// get cookie
function getCookie(name) {
    var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
    if(arr=document.cookie.match(reg))
        return unescape(arr[2]);
    else
        return null;
}
$.when( $.ready ).then(function() {
    var ssotoken = getCookie("sso_test_login");
    var usercode = getCookie("usercode");
    if(ssotoken != null && usercode != null) {
        var signout = $("#signout");
        $("#signout").html("Welcome " + usercode + "! <a href='/logout.nhn'>Sign out</a>");
        $("#signout").show();
        $("#signin").hide();
    }
});
```
