.. _webhook:
----------------------------
eformsign Webhook 사용하기
----------------------------
eformsign에 이벤트가 발생했을 때 발생한 이벤트의 정보를 고객 시스템/서비스로 알려주는 기능입니다. Webhook을 설정하면, 고객의 Webhook endpoint로 해당 이벤트 정보를 HTTP POST형식으로 알려줍니다.
.. tip::
Webhook의 endpoint는 고객의 client callback URL을 뜻합니다. Open API를 지속적으로 호출하여 변경사항을 체크하는 방법(polling)과 비교하여 불필요한 호출 없이 eformsign 상의 이벤트에 대한 정보를 얻을 수 있습니다.
시작하기
=========
.. _addwebhook:
Webhook 추가하기
--------------------
1. eformsign에 대표 관리자로 로그인 후, 메뉴에서 **[커넥트] > [API / Webhook]** 페이지로 이동합니다.
.. image:: resources/apikey1.PNG
:width: 700
:alt: 커넥트 > API/Webhook 메뉴 위치
2. **[Webhook 관리]** 탭을 선택하고 **Webhook 추가** 버튼을 클릭합니다.
.. image:: resources/webhook2.PNG
:width: 700
:alt: Webhook 추가 버튼
3. Webhook 추가 팝업창에 이름, Webhook을 수신할 URL(Endpoint URL), 활성 상태를 선택합니다.
.. image:: resources/Webhook_key1.png
:width: 500
:alt: Webhook 키 생성 팝업창
4. **적용 대상**\ 을 선택합니다. 적용 대상은 **모든 문서, 템플릿이 없이 만든 문서, 템플릿으로 만든 문서** 중에 선택할 수 있습니다.
.. image:: resources/Webhook_key2.png
:width: 500
:alt: Webhook 키 생성 팝업창 2
- **모든 문서:** 해당 회사에서 생성된 모든 문서에 대해 Webhook이 발송됩니다.
- **템플릿이 없이 만든 문서:** **내 파일로 문서 작성**\ 으로 템플릿 없이 생성한 문서에 대해 Webhook이 발송됩니다.
- **템플릿으로 만든 문서:** 선택한 템플릿으로 생성된 문서에 대해 Webhook이 발송됩니다.
.. note::
템플릿 선택은 다음과 같은 절차를 통해 수행하실 수 있습니다.
① **적용 템플릿 목록** 선택창을 클릭하면 템플릿 목록이 표시됩니다. 목록에서 추가하고자 하는 템플릿을 선택합니다. 이 때, 템플릿(|image1|)을 선택해야 합니다. 카테고리(|image2|)를 선택하면 적용 템플릿 목록에 추가되지 않습니다.
.. image:: resources/Webhook_select_template.png
:width: 500
:alt: Webhook 키 생성 팝업창 3
② 추가하고자 하는 템플릿을 선택 후, 우측의 **추가** 버튼을 클릭합니다.
.. image:: resources/Webhook_add_popup.png
:width: 500
:alt: Webhook 키 생성 팝업창 4
③ **적용 템플릿 목록**\ 에 선택한 템플릿이 추가 된 것을 확인할 수 있습니다. 이 절차를 반복하여, 여러 템플릿을 추가할 수도 있습니다.
.. image:: resources/Webhook_add_popup2.png
:width: 500
:alt: Webhook 키 생성 팝업창 5
5. **검증 유형**\ 을 선택합니다. 검증 유형은 **검증 없음, Bearer token, Basic authentication, eformsign signature** 중에서 선택할 수 있습니다. 각 검증 유형에 대한 설명은 `Webhook 검증하기 <#webhookauth>`__\을 확인해 주세요.
.. image:: resources/Webhook_add_popup3.png
:width: 500
:alt: Webhook 키 생성 팝업창 6
6. **등록** 버튼을 클릭하면 Webhook이 추가됩니다. **Webhook 관리** 목록에서 추가한 Webhook을 확인할 수 있습니다.
.. image:: resources/Webhook_add.png
:width: 700
:alt: Webhook 등록 완료
Webhook 관리하기
--------------------
Webhook 목록에서 각 Webhook 우측의 작업 버튼을 통해 관리 작업을 수행할 수 있습니다.
.. image:: resources/Webhook_manage1.png
:width: 700
:alt: 커넥트 > Webhook 관리
키 보기
~~~~~~~~~~~~~~~
검증 유형을 eformsign signature로 설정한 경우, Webhook 검증을 위해 필요한 공개 키를 확인할 수 있습니다.
**키 재발행** 버튼을 클릭해 키를 재발행할 수 있습니다. 키를 재발행 할 경우, 기존에 사용 중이던 키는 사용할 수 없게 됩니다.
검증 유형을 eformsign signature 이외의 다른 유형으로 설정한 경우, 빈 값이 표시됩니다.
.. image:: resources/Webhook_Key.png
:width: 400
:alt: 커넥트 > Webhook 키 보기
편집
~~~~~~~~~~~~~~~
등록된 Webhook의 이름, URL, 활성 상태, 적용 대상, 검증 유형을 편집할 수 있습니다.
삭제
~~~~~~~~~~~~~~~
등록된 Webhook을 삭제할 수 있습니다.
테스트
~~~~~~~~~~~~~~~
설정한 Webhook URL로 테스트 Webhook을 전송하고, 결과를 반환합니다.
테스트 Webhook의 Body는 다음과 같습니다.
설정한 검증 유형에 따라, 헤더에 관련 정보가 포함되어 전송됩니다.
.. code:: JSON
{
"webhook_id": "해당 Webhook ID",
"webhook_name": "해당 Webhook 이름",
"company_id": "회사 ID",
"event_type": "document",
"document": {
"id": "test_doc_id",
"document_title": "test_document_title",
"template_id": "test_template_id",
"template_name": "test_template_name",
"workflow_seq": 0,
"template_version": "1",
"history_id": "test_document_history_id",
"status": "doc_create",
"editor_id": "사용자 ID",
"updated_date": "현재 시간(UTC Long)"
}
}
.. note::
테스트 성공 여부에 따라 다음과 같이 팝업 메시지가 표시됩니다.
**테스트 Webhook 전송 성공 시**
.. image:: resources/webhook_success_popup.png
:width: 400
:alt: Webhook 전송 테스트 성공 시
**테스트 Webhook 전송 실패 시**
.. image:: resources/webhook_failed_popup.png
:width: 400
:alt: Webhook 전송 실패 시
**테스트 Webhook 전송 오류 발생 또는 응답이 없을 시**
.. image:: resources/webhook_error_popup.png
:width: 400
:alt: Webhook 오류 발생 시
.. _webhookauth:
Webhook 검증하기
========================
수신한 Webhook이 eformsign에서 호출한 정상적인 Webhook이 맞는지 검증할 수 있는 기능입니다.
Webhook 추가 혹은 편집 시, 다음과 같이 검증 유형을 선택할 수 있습니다.
.. image:: resources/Webhook_auth_type.png
:width: 500
:alt: Webhook 검증 유형 선택
- **검증 없음**
검증을 위한 별도의 정보 없이 Webhook을 발송합니다. 이 경우에도 이벤트 정보는 확인할 수 있지만, 수신한 Webhook이 정상 Webhook인지 검증할 수 없습니다.
- **Bearer Token**
검증을 위해 사전 설정한 토큰 값을 이용하는 방식입니다.
Webhook 추가 혹은 편집 시, 검증 유형을 **Bearer token**\ 으로 선택하고 토큰으로 사용할 값을 **값**\ 란에 입력합니다.
이와 같이 설정하면, Request Header의 Authorization 필드에 해당 값을 포함하여 Webhook을 전송하게 됩니다.
.. image:: resources/Webhook_auth_type1.png
:width: 500
:alt: Webhook 검증 유형 선택
예를 들어 위와 같이 값을 bearer_test_value라고 입력한 경우, Webhook 수신 시 Header에서 다음과 같은 내용을 확인할 수 있습니다.
.. code:: JSON
Authentication : Bearer bearer_test_value
이처럼 수신한 Webhook의 Header에서 Token 값을 추출한 후, 사전 설정한 값과 일치하는지 확인하는 방식으로 검증할 수 있습니다.
- **Basic Authentication**
검증을 위해 아이디와 비밀번호를 이용하는 방식입니다.
Webhook 추가 혹은 편집 시, 검증 유형을 **Basic authentication**\ 으로 선택하고 인증용으로 사용할 아이디와 비밀번호를 입력합니다.
이와 같이 설정하면, Request Header의 Authorization 필드에 사전 설정한 아이디와 비밀번호가 **아이디:비밀번호** 형태로 Base64 인코딩 한 값을 포함하여 Webhook을 전송하게 됩니다.
.. image:: resources/Webhook_auth_type2.png
:width: 500
:alt: Webhook 검증 유형 선택
예를 들어 위와 같이 아이디를 **eformsign**\ , 비밀번호를 **Webhook123!**\ 라고 입력한 경우, Webhook 수신 시 Header에서 다음과 같은 내용을 확인하실 수 있습니다.
.. code:: JSON
Authentication : Basic ZWZvcm1zaWduOldlYmhvb2sxMjMh
위의 예시에서 Basic 뒤의 값을 Base64 디코딩 시 **eformsign:Webhook123!**\ 가 됩니다.
이처럼 수신한 Webhook의 Header에서 Basic 뒤의 값을 Base64 디코딩하여 아이디와 비밀번호를 추출하고, 사전 설정한 아이디 및 비밀번호와 일치하는지 확인하는 방식으로 검증할 수 있습니다.
- **eformsign Signature**
검증을 위해 eformsign Signature 서명값을 이용하는 방식입니다.
.. note::
eformsign Signature는 비대칭 키 방식과 타원곡선 암호화(Elliptic curve cryptography)를 사용하는 서명 방식입니다. 서명 알고리즘은 SHA256withECDSA를 사용합니다.
Webhook 추가 혹은 편집 시, 검증 유형을 **eformsign signature**\ 로 설정하면 Request Header의 eformsign_signature 필드에 서명값을 포함하여 Webhook을 전송하게 됩니다.
Header 내용의 예시는 다음과 같습니다.
.. code:: JSON
eformsign_signature : 3045022100b9f1e0cdd21492cb5fa16dabff4c4402bf3efb9a9741a40a0d1c70aeda24bc8c02204a57ca1abab288e968a799e2fecbf18de9ab59c7c5814144b17f32553640a71a
서명 검증을 위한 샘플 코드
--------------------------
Webhook의 Header에서 eformsign_signature 값을 추출한 후, Webhook 목록에서 **키 보기**\ 버튼을 클릭하여 확인할 수 있는 Webhook 공개 키 및 수신한 Webhook의 Request Body 내용을 이용해 검증할 수 있습니다.
Java
~~~~~~~~~~~
아래 샘플 코드를 확인해 주세요.
Python
~~~~~~~~~~
키 포맷 처리용 라이브러리를 사용해야 합니다. 작업 전 다음 명령어를 통해 해당 라이브러리를 설치하세요.
.. code:: python
pip install https://github.com/warner/python-ecdsa/archive/master.zip
PHP
~~~~~~~~~
다음 예제의 keycheck.inc.php, test.php 파일이 동일한 경로에 위치하도록 한 후에 진행해야 합니다.
각 언어별 예제
~~~~~~~~~~~~~~~~~
다음은 각 언어별 예제입니다.
.. code-tabs::
.. code-tab:: java
:title: java
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
/**
* request에서 header와 body를 읽습니다.
*
*/
//1. get eformsign signature
//eformsignSignature는 request header에 담겨 있습니다.
String eformsignSignature = request.getHeader("eformsign_signature");
//2. get request body data
// eformsign signature 검증을 위해 body의 데이터를 String으로 변환 합니다.
String eformsignEventBody = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
eformsignEventBody = stringBuilder.toString();
//3. publicKey 세팅
String publicKeyHex = "이 곳에 발급받은 공개 키를 입력하세요";
KeyFactory publicKeyFact = KeyFactory.getInstance("EC");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(new BigInteger(publicKeyHex,16).toByteArray());
PublicKey publicKey = publicKeyFact.generatePublic(x509KeySpec);
//4. verify
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(publicKey);
signature.update(eformsignEventBody.getBytes("UTF-8"));
if(signature.verify(new BigInteger(eformsignSignature,16).toByteArray())){
//verify success
System.out.println("verify success");
/*
* 이곳에서 이벤트에 맞는 처리를 진행합니다.
*/
}else{
//verify fail
System.out.println("verify fail");
}
.. code-tab:: python
:title: Python 3.9.6
import hashlib
import binascii
from ecdsa import VerifyingKey, BadSignatureError
from ecdsa.util import sigencode_der, sigdecode_der
from flask import request
# request에서 header와 body를 읽습니다.
# 1. get eformsign signature
# eformsignSignature는 request header에 담겨 있습니다.
eformsignSignature = request.headers['eformsign_signature']
# 2. get request body data
# eformsign signature 검증을 위해 body의 데이터를 String으로 변환 합니다.
data = request.json
# 3. publicKey 세팅
publicKeyHex = "이 곳에 발급받은 공개 키를 입력하세요"
publickey = VerifyingKey.from_der(binascii.unhexlify(publicKeyHex))
# 4. verify
try:
if publickey.verify(eformsignSignature, data.encode('utf-8'), hashfunc=hashlib.sha256, sigdecode=sigdecode_der):
print("verify success")
# 이곳에 이벤트에 맞는 처리를 진행 합니다.
except BadSignatureError:
print("verify fail")
.. code-tab:: php
:title: PHP - keycheck.inc.php
openSslPublicKey = openssl_get_publickey($pem);
}
}
function Verify($message, $signature, $publicKey)
{
return openssl_verify($message, $signature, $publicKey->openSslPublicKey, OPENSSL_ALGO_SHA256);
}
?>
.. code-tab:: php
:title: PHP - test.php
.. _webhookevent:
Webhook 이벤트
====================
Webhook을 설정하면 eformsign에서 특정 이벤트 발생 시 설정한 Webhook URL로 이벤트 정보를 수신할 수 있습니다.
현재 제공 중인 `Webhook `_\ 은 다음과 같습니다.
Webhook 이벤트 종류
--------------------
현재 eformsign에서는 **문서 이벤트**\ 와 **PDF 생성 이벤트**\ 에 대해 Webhook을 발송하고 있습니다.
- **문서 이벤트:**\ eformsign에서 문서의 생성 또는 상태 변경 시 발생하는 이벤트입니다. event_type이 document이고, document Object를 포함하고 있습니다.
- **PDF 생성 이벤트:**\ eformsign에서 문서의 PDF 파일이 생성될 때 발생하는 이벤트입니다. event_type이 ready_document_pdf이고, ready_document_pdf Object를 포함하고 있습니다.
Webhook 구조
------------------
Webhook 이벤트 발생 시 사용자가 설정한 Webhook URL로 Webhook이 발송됩니다.
발송되는 Webhook의 Request Body 구조는 다음과 같습니다.
.. table::
=================== ====== ==================================== ===============================================
Name Type 설명 비고
=================== ====== ==================================== ===============================================
webhook_id String 이벤트를 발생시킨 Webhook의 ID
webhook_name String 이벤트를 발생시킨 Webhook의 이름
company_id String 회사 ID
event_type String 발생한 Webhook 이벤트의 종류 - document: 문서 이벤트
- ready_document_pdf: PDF 생성 이벤트
document Object 문서 이벤트의 상세 정보 문서 이벤트 발생 시에만 표시됨
(id, document_title, template_id, template_name,
workflow_seq, workflow_name, template_version,
history_id, status, editor_id, outside_token,
updated_date, mass_job_request_id 포함)
ready_document_pdf String 워크플로우 명칭 PDF 생성 이벤트 발생 시에만 표시됨
(document_id, document_title, workflow_seq,
workflow_name, template_id, template_name,
template_version, document_status,
document_history_id, export_ready_list,
mass_job_request_id 포함)
=================== ====== ==================================== ===============================================
.. note::
eformsign Webhook의 자세한 구조 및 예시는 `eformsign Webhook `__\ 에서 확인하실 수 있습니다.
.. _status:
문서 상태 코드
------------------
Webhook의 Request Body에는 문서 상태를 나타내는 코드가 포함되어 있습니다.
문서 이벤트의 경우 document.status, PDF 생성 이벤트의 경우 ready_document_pdf.document_status에 문서 상태 코드가 기재됩니다.
각 코드의 의미는 다음과 같습니다.
.. table::
========================== ====================================
Name 설명
========================== ====================================
doc_tempsave 초안(최초 작성자 문서 임시 저장 상태)
doc_create 문서 작성
doc_request_participant 참여자 요청
doc_accept_participant 참여자 승인
doc_reject_participant 참여자 반려
doc_request_reviewer 검토자 요청
doc_accept_reviewer 검토자 승인
doc_reject_reviewer 검토자 반려
doc_reject_request 반려 요청
doc_decline_cancel_request 반려 요청 거절
doc_delete_request 삭제 요청
doc_decline_delete_request 삭제 요청 거절
doc_cancel_request 요청 취소
doc_deleted 문서 삭제
doc_request_approval 결재 요청(구형 워크플로우)
doc_accept_approval 결재 승인(구형 워크플로우)
doc_reject_approval 결재 반려(구형 워크플로우)
doc_request_external 외부자 요청(구형 워크플로우)
doc_remind_external 외부자 재 요청(구형 워크플로우)
doc_open_external 외부자 열람(구형 워크플로우)
doc_accept_external 외부자 승인(구형 워크플로우)
doc_reject_external 외부자 반려(구형 워크플로우)
doc_request_internal 내부자 요청(구형 워크플로우)
doc_accept_internal 내부자 승인(구형 워크플로우)
doc_reject_internal 내부자 반려(구형 워크플로우)
doc_tempsave_internal 내부자 임시 저장(구형 워크플로우)
doc_complete 문서 완료
========================== ====================================
.. |image1| image:: resources/template_icon.png
.. |image2| image:: resources/category_icon.png