# Signing Service Tân Cảng (Hệ thống Ký số Tập trung & Desktop)

Dịch vụ ký số remote và usbtoken

# Chương 1: Giới thiệu Bài toán & Các Tính năng chính

Phần này cung cấp cái nhìn tổng quan về bối cảnh ra đời của Signing Service Tân Cảng, lý do tại sao hệ thống cần thiết, cùng với danh sách các tính năng cốt lõi được xây dựng để giải bài toán định danh và ký số điện tử của doanh nghiệp.

# 1. Bài toán Ký số & Mục tiêu Dự án

### Bối cảnh thực tế

Tại các cảng biển và văn phòng của Tân Cảng, số lượng tài liệu, hợp đồng, chứng từ giao nhận (E-DO), hóa đơn điện tử và các văn bản điều hành nội bộ được luân chuyển mỗi ngày là cực kỳ lớn. Cách làm thủ công bằng giấy tờ truyền thống gặp phải các vấn đề:

- Mất nhiều thời gian in ấn, luân chuyển và lưu trữ vật lý.
- Rủi ro thất lạc, làm giả chứng từ hoặc chi phí bảo quản tăng cao.
- Khó khăn trong việc tìm kiếm, truy xuất báo cáo, hay tích hợp luồng phê duyệt tự động trên hệ thống số.

### Lời giải cấu trúc số hóa

Để giải quyết triệt để vấn đề trên, dự án **Signing Service Tân Cảng** được hình thành. Mục tiêu của dự án là thiết lập một nền tảng **Ký số và Đóng dấu điện tử** hoàn thiện, giúp tự động hóa khâu xác thực văn bản. Nền tảng này đóng vai trò như một Service trung tâm chuyên biệt, cho phép các hệ thống nghiệp vụ (ví dụ: e-Office, Hệ thống điều hành Cảng URENCO) có thể dễ dàng gọi API để ráp chữ ký số vào tài liệu (đặc biệt là chuẩn PDF) theo đúng quy định pháp lý.

Hệ thống được thiết kế theo dạng **Client - Server** để giải quyết hai nhu cầu ký song song:

1. **Ký số bằng chứng thư số tập trung (Server-side/HSM):** Server sẽ tự động đóng dấu công ty hoặc ký phê duyệt tự động khối lượng lớn tài liệu mà không cần con người can thiệp.
2. **Ký số cá nhân (Client-side/USB Token):** Nhân viên cắm USB Token cá nhân vào máy tính để ký trực tiếp các văn bản được giao, đảm bảo tính chống chối bỏ.

# 2. Tính năng Ký số Tập trung (Server-side)

Tính năng quản trị chữ ký trên Server (Signing Web Service) là trung tâm điều phối của toàn hệ thống, đáp ứng yêu cầu xử lý hàng loạt:

- **Quản lý Chứng thư số Server-side:** Tích hợp với hệ thống **EJBCA** nội bộ thông qua các cơ chế (Cache) nhanh bằng Redis, giúp xác thực chứng thư (End Entity) và quản lý hiệu lực chứng thư mà không làm nghẽn hệ thống CA.
- **Ký tự động / Sinh chữ ký hàng loạt (Batch Signing):** Cho phép các hệ thống nghiệp vụ đẩy hàng loạt tài liệu PDF qua RESTful API, dịch vụ sẽ tự động đóng dấu (chữ ký tổ chức) và phản hồi lại file đã ký trong thời gian tính bằng phần nghìn giây.
- **Tùy biến hiển thị chữ ký (Visual Signature):** Cho phép truyền tọa độ (X, Y), số trang (Page) và hình ảnh (Con dấu đỏ/chữ ký nháy) để đính kèm trực tiếp lên bề mặt file PDF, giúp tài liệu dễ nhìn và đúng thể thức văn bản.

# 3. Tính năng Ký số Local (Client-side)

Song song với chữ ký Server, dự án cung cấp **Signing Desktop App** - một ứng dụng nhỏ nhẹ chạy nền dưới máy cá nhân của nhân sự:

- **Đọc &amp; Trích xuất chứng thư từ USB Token (PKCS#11):** Tích hợp driver của đa dạng các hãng USB Token (như Viettel, VNPT, BKAV, FPT...) theo cấu hình chuẩn, đọc và lấy public key để sinh payload ký.
- **Local Web Server trung gian:** Khởi chạy một server ở `localhost` (Port 6868/..) để frontend của hệ thống nghiệp vụ (trên trình duyệt Chrome/Edge) có thể gửi yêu cầu ký (LocalSignRequestDTO) thẳng xuống USB Token dưới máy tính.
- **Giao diện (UI) quản lý đơn giản:** Cung cấp các cửa sổ Pop-up (sử dụng thư viện FlatLaf hiện đại) giúp người dùng: 
    - Chọn chứng thư số từ danh sách Token đang cắm.
    - Nhập mã PIN an toàn.
    - Hiển thị thanh tiến trình (Loading Dialog) khi đang thực hiện ráp ký tài liệu nặng.

# 4. Các Tính năng Hỗ trợ & Vận hành

Để tạo thành một giải pháp hoàn chỉnh, Signing Service được trang bị thêm các module vệ tinh đắc lực:

- **Chuyển đổi định dạng Office sang PDF (Format Conversion):**
    
    
    - Người dùng hệ thống nghiệp vụ không cần tự xuất file PDF tĩnh. Dịch vụ hỗ trợ nhận trực tiếp các file Word (`.doc`, `.docx`) hoặc Excel (`.xls`, `.xlsx`).
    - Sử dụng thư viện **Aspose.Words / Aspose.Cells** tích hợp sẵn để chuyển đổi tự động văn bản thành tài liệu PDF chuẩn thức, giữ nguyên format bảng biểu trước khi thực thi việc đóng dấu chữ ký.
    - Xử lý khéo léo các lỗi định dạng giả mạo (ví dụ: File đuôi docx nhưng bản chất đã là PDF thì tự nhận diện được để by-pass bước convert).
- **Lưu vết và Audit Logging:**
    
    
    - Mọi hành vi gọi hệ thống từ Request OTP, lấy thông tin chứng thư, đến ký tài liệu đều được API `AuditLogAdminController` ghi nhận vào **SQL Server**.
    - Cung cấp vết thời gian (Timestamp), Client IP, User gọi API và nội dung giao dịch để phục vụ hậu kiểm, kế toán, hoặc thanh tra.
- **API linh hoạt (URENCO APIs &amp; Visual Only):**
    
    
    - Hỗ trợ riêng nhánh API đóng hình ảnh chữ ký không qua mã hóa chứng thư (`/sign-visual-only`) phục vụ phê duyệt nội bộ cấp thấp.
    - Định tuyến (Routing) mượt mà các API kế thừa từ hệ thống URENCO.

# Chương 2: Luồng Nghiệp vụ Chi tiết (Business Workflows)

Chương này mô tả chi tiết các trình tự xử lý và luồng dữ liệu (Data flow) của 3 nghiệp vụ cốt lõi trong hệ thống Signing Service Tân Cảng. Các biểu đồ tuần tự dưới đây giúp người đọc hình dung rõ cách các thành phần hệ thống tương tác với nhau từ lúc nhận yêu cầu đến khi trả về tài liệu đã ký.

# Trang mới



# 2.1. Luồng Ký số Tập trung (Web Service / Server-side)

Luồng Ký số Server-side được kích hoạt thông qua REST API trên **Signing Web Service**. Luồng này được sử dụng khi hệ thống e-Office tự động sinh tài liệu và cần đóng dấu đỏ công ty hoặc ký duyệt hàng loạt thông qua chứng thư lưu trên Server / HSM.

**Mô tả các bước:**

1. **Application (Client)** gửi yêu cầu `POST /api/sign` kèm theo file tài liệu (PDF, DOCX) và các thông tin Metadata (Tọa độ hình ảnh, Page, Base64 ảnh chữ ký).
2. **Web Controller** (`SigningController`) tiếp nhận, kiểm tra tính hợp lệ của Request và Token (nếu có Auth).
3. Nếu tài liệu là định dạng Office (Word/Excel), gọi qua module **Converter (Aspose)** để chuyển thành tịnh dạng chuẩn PDF.
4. Hệ thống kiểm tra Cache (Redis) đối với **EJBCA** để xác minh thư mục lưu thông tin chứng thư (End Entity).
5. Gọi API sang **EJBCA CA Server** ký hash của tài liệu và lấy dữ liệu chữ ký trả về.
6. Module **Signing Core (DSS)** ráp chữ ký và hình ảnh con dấu (Visual Signature) vào tài liệu PDF.
7. Ghi Log Audit vào Database và phản hồi kết quả trực tiếp cho Client.

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-03/scaled-1680-/Ea8image.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-03/Ea8image.png)

# 2.2. Luồng Ký số Local File (Desktop App / USB Token)

Luồng ký Local phục vụ cho nhu cầu nhân sự cá nhân cầm USB Token vật lý (Viettel, VNPT, FPT,...) để ký văn bản phê duyệt trên máy cá nhân.

**Mô tả các bước:**

1. Website/Portal nội bộ của doanh nghiệp tạo lệnh gọi **LocalSignRequest** xuống ứng dụng `Desktop App` đang chạy ngầm trên máy thông qua `http://localhost:6868/api/desktop/...`.
2. **Tọa độ** hoặc hình ảnh chữ ký được truyền theo xuống `DesktopSigningController`.
3. Ứng dụng Desktop App khơi gợi (pop-up) giao diện **UI (TokenProfileDialog/LoadingDialog)** để lấy Danh sách chứng thư số hiện hành đang cắm vào máy.
4. Yêu cầu nhập mã **PIN Token** từ người thao tác.
5. Desktop App liên kết thông qua thư viện `dss-token` tạo một kết nối PKCS#11 trực tiếp vào driver USB để ký file.
6. Ký thành công, Desktop App phản hồi REST API lại cho Website/Portal kết quả để Client upload file đó lên lại Server.

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-03/scaled-1680-/o9gimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-03/o9gimage.png)

# 2.3. Luồng Chuyển đổi và Đóng dấu (Visual Only)

Trong một số trường hợp, người dùng chỉ cần chèn hình ảnh phê duyệt (Con dấu báo cáo, chữ ký nháy hiển thị bằng hình ảnh) mà chưa cần áp hệ thống CA mã hóa Cryptography. Hệ thống ứng dụng Endpoint `/sign-visual-only`. Thông qua đó, nếu nhận được file Office, hệ thống sẽ thực thi luồng sau:

**Mô tả các bước:**

1. Tiếp nhận file định dạng `.doc` / `.docx` / `.xlsx` thông qua REST API.
2. Kiểm tra phần header nhị phân (Magic Bytes) xem file có bị đổi đuôi thủ công hay không (Ví dụ: `.pdf` đổi tên thành `.docx`). Nếu phát hiện là PDF nguyên gốc, hệ thống by-pass quy trình convert để tiết kiệm tài nguyên và bảo toàn file.
3. Nếu đúng là file Office, sử dụng **Aspose Engine (Aspose.Words / Aspose.Cells)** để convert từ cấu trúc DOM của tài liệu sang PDF chuẩn.
4. Đọc metadata (`image_info`) truyền xuống (tọa độ X, Y, số thứ tự trang cài đặt). Tính toán vị trí Absolute (Tuyệt đối) hoặc Reference (Tương đối) trên PDF.
5. Ráp chèn Hình Ảnh vào trang, lưu kết quả xuất file và trả về Client (Không qua khâu tương tác DSS CA/EJBCA).

# Chương 3: Kiến trúc Hệ thống & Cổng giao tiếp API

Chương này trình bày cái nhìn tổng quát về mô hình triển khai của hệ thống Signing Service Tân Cảng, sự tương tác giữa các vi dịch vụ, cũng như chi tiết đặc tả các cổng giao tiếp (API Interfaces) để các bên thứ 3 hoặc các nền tảng e-Office tích hợp.

# 3.1. Sơ đồ Kiến trúc Tổng thể (System Architecture)

Giải pháp được xây dựng theo mô hình **Client-Server phân tán (Distributed)** kết hợp bộ đệm (Cache) và kiến trúc Agent cục bộ dành cho chữ ký cứng.

[![mermaid-diagram.png](https://docs.lifetex.vn/uploads/images/gallery/2026-03/scaled-1680-/mermaid-diagram.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-03/mermaid-diagram.png)

**Thành phần chính:**

1. **Signing Web Service (Server):** Điểm vào chính của các yêu cầu ký tập trung. Bao gồm bộ Converter (Aspose) và Signing Core (DSS/PDFBox) xử lý dữ liệu chuẩn PAdES.
2. **Local Desktop Agent (Client):** Ứng dụng trung gian giúp Web Browser truy xuất trực tiếp chứng thư số từ USB vật lý (không bị trình duyệt chặn giao thức bảo mật) dựa vào endpoint REST API cục bộ.
3. **Hạ tầng hỗ trợ (Redis/MSSQL):** Redis giúp cache `EJBCAService` tránh tải nặng cho CA nội bộ với mỗi lượt request. SQL Server (MSSQL) lưu log và phân quyền truy cập.

# 3.2. Danh sách Web API Chính (Server-Side)

Đây là các endpoint chủ lực trên máy chủ (nằm trong <span class="inline-flex break-all leading-tight">SigningController</span>), sử dụng JSON làm phương tiện trao đổi (`application/json` hoặc `multipart/form-data`). Hệ thống yêu cầu Header `Token-Signing` (phiên ký hợp lệ) cho hầu hết các API nghiệp vụ.

### 1. Nhóm API Xác thực OTP &amp; Cấp quyền

- **`POST /api/sign/request-otp`**: Yêu cầu tạo mã OTP từ hệ thống. Dùng cho luồng bảo mật bước 2.
- **`POST /api/sign/verify-otp`**: Xác thực OTP để hệ thống cấp/kiểm tra phiên ký hợp lệ.

### 2. Nhóm API Ký số &amp; Xử lý Tài liệu

- **`POST /api/sign/document`**: 
    - API chính để ký dữ liệu tập trung (Dùng chứng thư máy chủ EJBCA).
    - **Input:** Hỗ trợ Upload File (`@ModelAttribute WebSignRequestDTO`), tự động nhận diện định dạng (DOCX, XLSX, PDF) để convert qua PDF.
- **`POST /api/sign/document-with-image`** &amp; **`POST /api/sign/documents-with-image`**: 
    - Hỗ trợ ký số và chèn ảnh (Visual Signature). Yêu cầu truyền mảng `imageMetadata` chứa thông tin tọa độ.
- **`POST /api/sign/document-initial-signature`**: 
    - Chuyên dùng cho nghiệp vụ Ký nháy, chèn hình ảnh/con dấu chữ ký ở các tọa độ linh hoạt.

### 3. Nhóm API Quản trị &amp; Audit Log

- **`GET /api/admin/audit-logs/range`** (Controller: `AuditLogAdminController`): Lấy danh sách vết giao dịch ký.
- **`GET /api/diagnostic/test-connection`** (Controller: `EmailDiagnosticController`): Gửi cảnh báo SMS/Email kiểm tra tình trạng kết

# 3.3. Danh sách Desktop API (Cục bộ localhost:6868)

Để tiện cho Web frontend gửi lệnh ký vào máy trạm, ứng dụng Desktop mở sẵn cổng RESTful trực tiếp trên máy người dùng (qua <span class="inline-flex break-all leading-tight">DesktopSigningController</span>). Các endpoint này giao tiếp trực tiếp với USB Token.

- **`POST /api/desktop/sign`**: Endpoint ký file PDF cơ bản.
- **`POST /api/desktop/document`**: Endpoint ký hỗ trợ convert file (Word, Excel) trước khi ký.
- **`POST /api/desktop/document-with-image`**: Endpoint ký và chèn hình ảnh con dấu (Tương đương chức năng trên Server nhưng ký bằng Token Local). Hỗ trợ xác định vị trí chèn ảnh chèn lấp (OVERLAY), trái (LEFT), phải (RIGHT) v.v.

# Chương 4: Cấu trúc Source Code & Modules

Dự án Signing Service Tân Cảng được thiết kế theo kiến trúc Maven Multi-Module dựa trên nền tảng Spring Boot. Cách tiếp cận này giúp cô lập rành mạch logic lõi (Core Signing) ra khỏi các giao tiếp bên ngoài (Web API, Desktop API), tối ưu việc tái sử dụng code và dễ dàng bảo trì về sau.

# 4.1. Module signing-common

Đây là module cơ sở nhất, không chứa logic xử lý phức tạp mà chỉ chứa các định nghĩa (Definitions) được sử dụng chung cho toàn bộ các module khác trong hệ thống.

- **Thành phần chính:**
    
    
    - **DTO (Data Transfer Objects):** Các class request/response trung gian như `SignRequestDTO`, `LocalSignRequestDTO`, `OTPResponse`, v.v.
    - **Models/Enums:** Các định nghĩa trạng thái ký, loại chứng thư hoặc các tham số quy định hệ tọa độ hình ảnh.
    - **Exceptions:** Các Custom Exception chung.
    - **Utils:** Các lớp Helper dùng chung như Validate chuỗi, thao tác Date/Time.
- **Sự phụ thuộc:** Không phụ thuộc vào module nào khác trong hệ thống.

# 4.2. Module signing-core

Đây là "trái tim" của hệ thống, nơi thực hiện toàn bộ các nghiệp vụ mật mã học (Cryptography) và can thiệp vật lý vào file PDF.

- **Nhiệm vụ:**
    
    
    - Khởi tạo và thiết lập các API tích hợp với thư viện **DSS (Digital Signature Services)** của liên minh Châu Âu (eu.europa.ec.joinup.sd-dss).
    - Thực thi việc băm tài liệu (Document Hashing) và cấp phát đối tượng `PAdES` Signature.
    - Quản lý nghiệp vụ Custom Validation cho file PDF.
- **Thành phần kỹ thuật nổi bật:**
    
    
    - Cung cấp các lớp Handler mở rộng như bộ thư viện đọc/ghi file `PDFBox`.
    - Các package `eu.europa.esig.dss.pdf...` được custom lại (nếu có) để xử lý triệt để các lỗi hiển thị (Visual Signature) mà bản gốc DSS đôi khi không hỗ trợ trơn tru ở phông chữ tiếng Việt.

# 4.3. Module signing-web-service

Đây là khối ứng dụng Web chính (Main Application) vận hành ở phía Server-side. Module này được đóng gói thành một Docker Container độc lập phục vụ cho ký tập trung.

- **Nhiệm vụ:**
    
    
    - Expose toàn bộ các RESTful API phục vụ Web Portal và Mobile App.
    - Quản lý Security (Xác thực JWT/OTP, phân quyền Admin).
    - Giao tiếp trực tiếp với cơ sở dữ liệu `SQL Server` và tầng Cache `Redis`.
    - Kết nối EJBCA (Hệ thống CA Manager) để yêu cầu ký qua kết nối bảo mật.
    - Gọi khối công cụ **Aspose (Words/Cells)** để Convert định dạng Office (.docx, .xlsx) sang PDF chuẩn thức trước khi đưa vào module `signing-core`.
- **Cấu trúc Package tham khảo:**
    
    
    - `/controller`: Các endpoint REST (VD: <span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">SigningController</span></span></span>).
    - `/service`: Logic gọi API nội bộ, logic OTP, thao tác file.
    - `/repository`: Thao tác với SQL Database (Audit Logs, Users).
    - `/config`: Cấu hình Security, Swagger, Redis Cache.

# 4.4. Module signing-desktop

Đây là ứng dụng Client-side dành riêng cho máy nhân sự, giúp khắc phục nhược điểm trình duyệt web không thể đọc trực tiếp cổng USB vật lý.

- **Nhiệm vụ:**
    
    
    - Chạy nền một Web Server cục bộ (`http://localhost:6868/api/desktop/*`) tiếp nhận lệnh ký từ màn hình trình duyệt Web Portal e-Office.
    - Nhận biết và quét (Scan) các USB Token (PKCS#11) đang gắn trên máy tính thông qua file <span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">token-config.json</span></span></span>.
    - Hiển thị giao diện người dùng (UI) tối giản bằng Java Swing / FlatLaf giúp người dùng: 
        - Chọn chứng thư số cá nhân.
        - Nhập mã PIN an toàn.
        - Xem thanh tiến trình Loading khi file đang xử lý.
    - Gắn hình ảnh chữ ký và ráp kết quả trả về cho Frontend.
- **Thành phần kỹ thuật nổi bật:**
    
    
    - `/ui`: Chứa các cửa sổ Pop-up, `CertificateListDialog`, `TokenProfileDialog`.
    - `/controller` &amp; `/service`: Tiếp nhận API Custom và điều phối gọi Token.

# 4.5. Module signing-scanner-sdk

*Khối này được module hoá để độc lập hóa phần tích hợp ngoại vi nếu dự án mở rộng hỗ trợ nhận dạng chữ ký viết tay/máy quét vật lý).*

- **Nhiệm vụ:**
    - Cung cấp các SDK hoặc API nội bộ xử lý luồng thao tác với thiết bị phần cứng thứ 3.
    - Tách bạch logic ra khỏi `signing-core` giúp tránh việc hệ thống chính phải ôm đồm quá nhiều Driver máy Scan không cần thiết.

---

## Sơ đồ Phụ thuộc (Dependency Graph)

Dưới đây là sơ đồ tham chiếu lẫn nhau (`<dependency>`) trong file cấu hình <span class="inline-flex break-all leading-tight">pom.xml</span>:

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-03/scaled-1680-/jKjimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-03/jKjimage.png)

*Nhìn vào mô hình, ta thấy **Web** và **Desktop** là 2 lớp trên cùng (Tầng Ứng dụng), có thể tái sử dụng chung toàn bộ logic lõi của **Core***

# Chương 5: Hướng dẫn Cài đặt & Triển khai

Chương này hướng dẫn chi tiết cách thức thiết lập môi trường, đóng gói và triển khai ứng dụng cho cả 2 khối cấu thành nên Signing Service Tân Cảng: Web Service (chạy trên Server) và Desktop App (chạy trên máy trạm của người dùng).

# 5.1. Yêu cầu Hệ thống (Prerequisites)

Để đảm bảo hệ thống có thể biên dịch và chạy trơn tru, máy chủ / máy lập trình viên cần đáp ứng các điều kiện sau:

- **Môi trường Java:** Khuyến nghị sử dụng cài đặt **JDK 17**.
- **Trình quản lý gói:** **Maven** `3.8+` (Hoặc dùng file <span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">mvnw</span></span></span> cung cấp sẵn trong source code).
- **Môi trường Máy chủ (Web Service):** Linux/Windows Server đã cài đặt sẵn **Docker** và **Docker Compose**.
- **Môi trường Đóng gói (Desktop App):** Máy tính Windows để đóng gói JRE custom. Yêu cầu có cài đặt **WiX Toolset (v3.x)** nếu muốn build file cài dạng `.msi`.
- **Database &amp; Cache:** MSSQL Server (2016 trở lên) và Redis Server (Khuyến nghị Redis v7+).
- **Source code**: [http://192.168.0.95/nam/signing\_service\_tan\_cang.git](http://192.168.0.95/nam/signing_service_tan_cang.git) nhánh [dev\_namdh\_app\_signing\_desktop](http://192.168.0.95/nam/signing_service_tan_cang/-/tree/dev_namdh_app_signing_desktop)

# 5.2. Hướng dẫn Triển khai Signing Web Service (Server)

Ứng dụng Web Service được tối ưu để hoạt động trong Docker Container, cung cấp khả năng khởi tạo nhanh và độc lập môi trường.

### Cách 1: Chạy trực tiếp qua Docker Compose (Khuyến nghị)

Hệ thống đã cung cấp sẵn file <span class="inline-flex break-all leading-tight">docker-compose.yml</span>. Khi gọi lệnh `docker-compose up`, nó sẽ tự động triển khai 2 service: `redis` và ứng dụng `kyso-service`. *(Lưu ý: Bạn cũng có thể kéo Image từ Harbor nếu có tài khoản, ví dụ: `harbor.lifetex.vn/kysotaptrung/kyso-service`)*

**Các biến môi trường (Environment Variables) cần thay đổi trước khi chạy:** Mở file <span class="inline-flex break-all leading-tight">docker-compose.yml</span> và kiểm tra phần `environment` của service `kyso-service`:

```yaml
environment:
  # Kết nối Cơ sở dữ liệu MS SQL Server
  SPRING_DATASOURCE_URL: jdbc:sqlserver://<DB_HOST>:<PORT>;databaseName=<DB_NAME>;encrypt=true;trustServerCertificate=true
  SPRING_DATASOURCE_USERNAME: <User_DB>
  SPRING_DATASOURCE_PASSWORD: <Pass_DB>

  # Cấu hình Redis (Thông qua container nội bộ)
  SPRING_DATA_REDIS_HOST: kyso-redis
  SPRING_DATA_REDIS_PORT: 6379

```

**Lệnh khởi động dịch vụ:**

```bash
# Đi vào thư mục chứa source signing_service_tan_cang
# Build image và chạy ngầm (Detached mode)
docker-compose up -d --build

```

Log hệ thống có thể được xem thông qua lệnh: `docker logs -f kyso-service`. API cổng chính thức hoạt động trên port **`6868`**.

### Cách 2: Triển khai trực tiếp bằng file JAR

Nếu không dùng Docker, bạn có thể build file `.jar`:

```bash
mvn clean package -pl signing-common,signing-core,signing-scanner-sdk,signing-web-service -am -DskipTests
```

Sau đó chạy file JAR kèm theo file `application.yml`:

```bash
java -jar signing-web-service/target/signing-web-service-0.0.1-SNAPSHOT.jar
```

# 5.3. Đóng gói & Cài đặt Signing Desktop App (Client)

Client App được tối ưu hóa đặc biệt. Thay vì phải yêu cầu hàng trăm nhân sự dùng máy tính văn phòng tự tải JDK/JRE về để chạy lệnh `java -jar`, ứng dụng Desktop được **nhúng (bundle) thẳng JRE** (Custom JRE) vào bên trong thông qua công cụ `jlink` và `jpackage`. Nó biến Web Service local thành một file `<Tên-App>.exe` hoặc `<Tên-App>.msi` độc lập.

Quy trình đóng gói đã được gom gọn tự động hóa toàn bộ trong script **<span class="inline-flex break-all leading-tight">package\_desktop.bat</span>**.

### Hướng dẫn chạy chạy script đóng gói:

1. Đảm bảo biến môi trường máy tính của bạn đã trỏ chuẩn xác `%JAVA_HOME%` (JDK 17 của thư mục bin). Nếu quên, script sẽ báo lỗi không tìm thấy `jlink` hay `jpackage`.
2. (Tùy chọn) Cài đặt phần mềm **WiX Toolset (v3.x)** tại `https://wixtoolset.org/releases/`. Đây là thư viện gốc do Microsoft hỗ trợ để đóng gói hệ thống dưới định dạng Cài đặt chuẩn `.msi` (Dễ dàng để IT cảng push policy GPO tự động cài cho toàn bộ máy nhánh).
3. Mở cửa sổ Command Prompt (<span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">cmd</span></span></span>) hoặc Terminal, chạy lệnh:

```bash
package_desktop.bat
```

### Diễn giải 5 bước cấu thành của Script:

- **\[1/5\] Build Source Code:** Script tự động gọi `mvn clean package -DskipTests` riêng cho module `signing-desktop` (và các module con tham chiếu).
- **\[2/5\] Custom JRE (jlink):** Lọc bỏ bớt các thư viện thừa (như javafx, jdk.compiler không cần thiết), tạo ra một máy ảo Java thu nhỏ (giảm dung lượng) vào thư mục `custom-jre`. Tính năng `java.smartcardio` được thêm vào bắt buộc để tương tác được USB Token lõi.
- **\[3/5\] Portable Image (jpackage):** Gom mã nguồn Desktop (file `.jar`) làm nhân của file EXE (App Image). Kết quả cho ra ở thư mục `dist/signing-desktop`. Ai copy thư mục này ném sang máy tính khác chạy luôn file `.exe` bên trong là hệ thống sẽ bật.
- **\[4/5\] Check WiX Toolset:** Kiểm tra tool `candle` của WiX. Nếu không có ở máy build, sẽ skip Bước 5.
- **\[5/5\] Build Windows Installer (.msi):** Gom cả Bundle thư mục Portable thành 1 file Install System duy nhất. Khi người dùng chạy, nó sẽ tự cài vào `C:\Program Files\`, tạo lối tắt đè ngoài màn hình Desktop (Shortcut) và trong thanh Start Menu.

Kể từ nay, bạn chỉ việc gởi file **`.msi`** hoặc file **`.exe` portable** đã sinh ở thư mục `dist/` cho kế toán/nhân sự để cài đặt sử dụng ký bằng Token một cách mượt mà.

# Chương 6: Cấu hình Hệ thống (System Configuration)

Để hệ thống hoạt động chính xác với hạ tầng của đối tác/khách hàng, Signing Service Tân Cảng cung cấp các file cấu hình tách biệt hoàn toàn khỏi mã nguồn. Chương này giải thích các file cấu hình quan trọng nhất trên hệ thống.

# 6.1. Cấu hình Web Service (application.yml)

Mọi thông số kết nối trọng yếu của API Server được đặt trong thư mục `src/main/resources/application.yml` (khi lập trình) hoặc ghi đè bằng **Environment Variables** (khi chạy Docker).

### 1. Kết nối Cơ sở dữ liệu (MSSQL Server)

Hệ thống sử dụng SQL Server để lưu thông tin Audit Log (lịch sử ký) và quản lý User/Role phân quyền truy cập.

```yaml
spring:
  datasource:
    url: jdbc:sqlserver://192.168.0.92:1433;databaseName=signing_db;encrypt=true;trustServerCertificate=true
    username: lifetex
    password: LTLT@2025
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
  jpa:
    hibernate:
      ddl-auto: update # (Chỉ nên dùng update ở môi trường Dev, Production nên dùng validate/none)
```

### 2. Cấu hình Redis (EJBCA Cache)

Hệ thống EJBCA CA có tần suất truy vấn siêu lớn ("Kiểm tra chứng thư này còn tồn tại không?"). Để tránh sập tầng mạng CA, ta cấu hình Redis để lưu tạm (Cache) dữ liệu này.

```yaml
spring:
  data:
    redis:
      host: kyso-redis # Trỏ tới container redis nếu dùng chung docker-network
      port: 6379 
      # Có thể thiết lập thêm 'password' nếu cụm Redis Server yêu cầu auth.
```

### 3. Cấu hình Hệ thống Email &amp; SMS (Dùng cho Notification Diagnostics)

Các thông báo cảnh báo hệ thống (như khi không gọi được CA Server) sẽ được đẩy qua giao thức SMTP.

```yaml
spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: admin@domain.com
    password: app-password
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
```

# 6.2. Cấu hình Máy trạm Desktop ( token-config.json )

Do USB Token (SmartCard) đến từ rất nhiều định dạng nhà cung cấp khác nhau (Viettel, VNPT, FPT, BKAV, HILO), mỗi hãng lại dùng một file Driver `.dll` (trên Windows) riêng biệt.

Ứng dụng `signing-desktop` quản lý cấu hình các Token này thông qua file **<span class="inline-flex break-all leading-tight">token-config.json</span>** nằm tại thư mục gốc của file thực thi.

**Định dạng JSON mẫu:**

```json
[
  {
    "id": "95893e6d-ef56-46ff-981f-5a73f81982b6",
    "name": "USB_HILO_CA",
    "libraryPath": "C:\\Windows\\System32\\hiloca_csp11_v1.dll",
    "slotIndex": 0
  },
  {
    "id": "e5d...-...",
    "name": "VIETTEL_CA",
    "libraryPath": "C:\\Windows\\System32\\viettel-ca_v6.dll",
    "slotIndex": 0
  }
]
```

**Giải thích thông số:**

- <div>  
    </div><span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">name</span></span></span>: Tên định danh của dòng USB Token (để hiển thị trên giao diện `TokenProfileDialog` cho người dùng chọn).
- `libraryPath`: Đường dẫn tuyệt đối trỏ tới file thư viện **PKCS#11** (File `.dll` / `.so` / `.dylib`) của hãng đang cài trong hệ điều hành.
- `slotIndex`: Thứ tự khe cắm thiết bị lưu trữ trên Driver (mặc định đa số là `0`).

> TIP
> 
> **Mẹo chuẩn đoán:** Nếu hệ thống chạy Desktop App bị treo và báo *"Module PKCS11 không khả dụng"*, hãy mở file **<span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">token-config.json</span></span></span>** và kiểm tra xem biến `libraryPath` có đúng với đường dẫn cài của hãng cung cấp hay không.

# 6.3. Cấu hình giao tiếp EJBCA Server

Các cấu hình giao tiếp mã hóa (Keystore / Truststore) để kết nối an toàn với máy chủ cấp phát EJBCA thông qua Rest/SOAP API (nếu có yêu cầu Mutual-TLS) thường nằm trong các tham số Custom Properties tự định nghĩa.

```yaml
ejbca:
  client:
    base-url: "https://ca-server.tancang.com.vn:8443/ejbca/ejbca-rest-api"
    keystore-path: "classpath:certs/ejbca_client.p12"
    keystore-password: "changeit"
    truststore-path: "classpath:certs/truststore.jks"
    truststore-password: "changeit"
```

Khi mã nguồn khởi tạo (tại module `signing-core`), lớp Service sẽ nạp cấu hình SSL/TLS này vào Context để duy trì liên kết an toàn tuyệt đối với máy chủ bảo mật của phía bên trong hạ tầng (Internal Network).

# Chương 7: Hướng dẫn dành cho Lập trình viên (Developer Guide)

Chương này cung cấp những kiến thức và quy ước cần thiết nhất cho một lập trình viên (Developer) mới tham gia vào dự án, để có thể nhanh chóng làm quen, build source code và debug lỗi hệ thống Signing Service Tân Cảng.

# 7.1. Cấu trúc Quản lý Dependency (Parent POM)

Toàn bộ dự án đi theo mô hình **Maven Multi-Module**, được kiểm soát chặt chẽ bởi file

<div id="bkmrk-">  
</div><span class="inline-flex break-all leading-tight">pom.xml</span> nằm ở gốc dự án (Root Directory). Đây là nơi khai báo `dependencyManagement`.

### Lý do của kiến trúc này:

1. Đảm bảo toàn bộ 5 module con (`signing-core`, `signing-web-service`, v.v.) luôn **đồng nhất một phiên bản thư viện**.
2. Khi muốn nâng cấp hệ thống Spring Boot, Lõi DSS hoặc Aspose, lập trình viên chỉ cần thay đổi tại `<properties>` của Root POM. Không cần đi sửa rải rác.

Ví dụ các Properties quan trọng:

```xml
<properties>
    <java.version>17</java.version>
    <dss.version>6.0</dss.version> <!-- Phiên bản cốt lõi Digital Signature Services EU -->
</properties>
```

Đặc biệt, hệ thống sử dụng `dss-pades-pdfbox` (bản 6.0.1.d4j.1) kết hợp với các Custom Handler tự phát triển trong thư mục `eu.europa.esig.dss` ở module lõi.

<p class="callout warning">Tuyệt đối không khai báo `<version>` thủ công vào các dependency bên dưới các module con (ví dụ ở <span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">signing-web-service/pom.xml</span></span></span>). Mọi version phải tham chiếu từ thẻ `<dependencyManagement>` của Parent POM.</p>

# 7.2. Hướng dẫn Môi trường & Build Source

**Hướng dẫn cài đặt môi trường**

 **Môi trường phát triển hệ điều hành Windows**

\- Cài đặt **IntelliJ IDEA** ( [Link cài đặt Intellij IDEA](https://www.jetbrains.com/idea/download/download-thanks.html?platform=windows)**[ ](https://www.jetbrains.com/idea/download/download-thanks.html?platform=windows)**)

\- Hoặc cài đặt **Visual Studio Code** ( [Link cài đặt Visual Studio Code](https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user) )

\- Cài đặt **JDK-17** ( [Link cài đặt JDK-17](https://download.oracle.com/java/17/archive/jdk-17.0.12_windows-x64_bin.exe) )

Thêm java vào biến môi trường:

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/Greimage.png) ](https://docs.lifetex.vn/uploads/images/gallery/2026-04/Greimage.png)[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/m4Wimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/m4Wimage.png)

\- Cài đặt **Maven** ( [Link tải maven](https://dlcdn.apache.org/maven/maven-3/3.9.14/binaries/apache-maven-3.9.14-bin.zip) )

Giải nén thư mục và thêm vào biến môi trường

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/s28image.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/s28image.png)

Kiểm tra java và maven đã được cấu hình chưa:

```bash
java --version
mvn -v
```

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/Sokimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/Sokimage.png)

1. **Clone mã nguồn &amp; Mở IDE:**
    - Hỗ trợ tốt nhất trên **IntelliJ IDEA.**
    - **Ví dụ sử dụng IDE Visual Studio Code**

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/Jpoimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/Jpoimage.png)

Clone source code: [http://192.168.0.95/nam/signing\_service\_tan\_cang.git](http://192.168.0.95/nam/signing_service_tan_cang.git) nhánh **dev\_namdh\_app\_signing\_desktop**

Mở terminal vscode lên và clone source code về bằng lệnh sau:

```bash
git clone --single-branch --branch dev_namdh_app_signing_desktop http://192.168.0.95/nam/signing_service_tan_cang.git kyso_service 
```

Nhập thông tin tài khoản Gitlab để clone source code về với tên thư mục "**kyso\_service**"

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/3wGimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/3wGimage.png)

Mở thư mục Project **kyso\_service** lên để thực hiện phát triển phần mềm

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/75uimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/75uimage.png)

---

1. - Khi Import, chọn Import theo chuẩn Maven Project tại thư mục Gốc.
2. **Build Dự án Local:** Mở terminal và gõ lệnh: (Bỏ qua Unit Test để tiết kiệm thời gian)
3. ```bash
    mvn clean install -DskipTests
    ```
    
    Build source thành công  
    [![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/FzBimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/FzBimage.png)
4. **Chạy Local Signing Web Service:**

**Với môi trường phát triển là VScode:**

```bash
cd signing-web-service\target
java -jar signing-web-service-0.0.1-SNAPSHOT.jar
```

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/3n1image.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/3n1image.png)

Port mặc địch của định của dịch vụ khi chạy lên là **6868** (Có thể cấu hình chay port khác bằng lệnh sau)

```bash
java -jar signing-web-service-0.0.1-SNAPSHOT.jar --server.port=<port_service>
```

**Với môi trường phát triển là IntelliJ IDEA**

1. - Trỏ IDE vào thư mục module `signing-web-service`.
    - Tìm Main class `SigningWebServiceApplication.java` và thiết lập Run Configuration.
2. [![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/jS8image.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/jS8image.png)
3. - **Chú ý:** Web Service cần có cấu hình `application.yml` trỏ đúng vào CSDL và Server Redis (Trường hợp không có DB thật, có thể dựng Docker Container Redis &amp; SQL Server Local trước khi chạy).
4. **chạy thành công**

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-04/scaled-1680-/toVimage.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-04/toVimage.png)

1. **Chạy Local Signing Desktop (Cổng 6868):**
    - Trỏ IDE vào thư mục module `signing-desktop`.
    - Chạy class `SigningDesktopApplication.java`. (Ứng dụng chạy Swing UI, cần gắn thử một USB Token thật vào máy để test tính năng Load Danh sách chứng thư).

# 7.3. Cách Debug (Kiểm thử) các Tính năng Phức tạp

### Gỡ chặn CORS khi gọi từ môi trường Frontend (Local Web Proxy)

Vì Desktop App chạy ở cổng `localhost:6868` nhưng Frontend Portlet lại chạy trên tên miền của hệ thống E-Office (Ví dụ `https://portal.tancang.com.vn`), nên mặc định trình duyệt như Chrome/Edge sẽ chặn **CORS (Cross-Origin Resource Sharing)**.

Để lập trình Frontend kiểm thử chức năng gọi API ký xuống Local Desktop, **Lập trình viên cần tắt tường lửa bảo mật của trình duyệt Chrome**:

- Mở command line, khởi động trình duyệt bằng luồng riêng biệt (Vô hiệu hóa Web Security và định tuyến User Data cục bộ):

```
chrome.exe --disable-web-security --user-data-dir="C:\ChromeDevSession"
```

- Tính năng này đã được ghi chép trong nội bộ dự án, nhưng **Bắt buộc phải tắt cờ này khi mang lên môi trường Production** (Xử lý dứt điểm trong code bằng config Spring `@CrossOrigin` trên Controller Local).

### Môi trường giả lập USB Token

Trong quá trình phát triển (Dev) nếu không có USB Token cứng do công ty cung cấp, bạn có thể tạo một file **Mock PKCS12 (.p12)** và thiết đặt `dss-token` trong mã nguồn đọc thẳng từ file vật lý này thay vì giao tiếp qua thư viện `.dll` / `PKCS#11`. *Xem code tham khảo tại class `UsbTokenService.java`.*

# Chương 8: Vận hành & Xử lý sự cố thường gặp (Troubleshooting)

Quá trình vận hành Signing Service Tân Cảng trải qua sự đóng góp của nhiều luồng kết nối phân tán. Chương này liệt kê các lỗi phổ biến mà quản trị viên, chuyên viên hỗ trợ (Support/IT) thường gặp và cách check log bắt bệnh chính xác.

# 8.1. Lỗi Không nhận USB Token trên Desktop App

Luồng chạy ứng dụng Desktop phụ thuộc sát sao vào độ ổn định phần cứng máy tính và Driver hãng.

**Hiện tượng:** Ứng dụng Desktop chạy, nhưng khi gọi lệnh ký thì pop-up báo *"Không tìm thấy thiết bị Token"* hoặc văng lỗi `PKCS11Exception`. **Cách xử lý:**

1. Rút ra cắm lại USB Token, đảm bảo trên thanh System Tray Windows ở góc dưới màn hình đã hiển thị phần mềm ký của thiết bị (Ví dụ: Viettel-CA Manager).
2. Kiểm tra tệp <div>  
    </div>**<span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">token-config.json</span></span></span>**: 
    - Mở file **<span class="context-scope-mention"><span class="inline-flex items-center gap-0.5 rounded-md align-middle text-sm font-medium transition-[opacity,background-color] cursor-pointer hover:bg-gray-500/20 select-text translate-y-[-1px]" draggable="true"><span class="inline-flex break-all leading-tight">.json</span></span></span>** này tại thư mục chạy của Desktop App.
    - Kiểm tra đường dẫn chuỗi `"libraryPath": "C:\\Windows\\System32\\eps2003csp11.dll"` có đúng tới file `.dll` đang nằm sẵn trong Windows không. Đôi lúc bản Update của hãng đổi tên `.dll` gây hỏng tiến trình hook.
3. Đóng ứng dụng Desktop (Quit ở System Tray) và chạy lại. Lỗi về session thẻ nhớ SmartCard thường sẽ hết.

# 8.2. Lỗi Chuyển đổi Khống Format (File Conversion Issues)

1. Một trong những vấn đề đau đầu nhất là khi người dùng Upload một file không chính thống nhưng "vô tình hoặc cố ý" bị đổi sai định dạng đuôi file.
    
    **Hiện tượng:** Quăng lỗi `UnsupportedFileFormatException` khi đang thực thi bộ chuyển đổi Aspose.Words (ví dụ: Chuyển `.docx` sang `.pdf`). **Nguyên nhân gốc rễ (Root Cause):** File thực chất đã là chuẩn `.pdf` bên trong, nhưng người dùng (hoặc hệ thống tạo tự động) lại đang lưu tên nó với đuôi mở rộng là `.docx`. Bộ máy Aspose Words tiếp nhận file tưởng đây là Word, mở ra thấy sai logic binaire của Office thì quăng lỗi. **Cách xử lý &amp; Cách dự án giải quyết:** Vấn đề này đã được Patch trong nhánh xử lý của
    
    **<span class="inline-flex break-all leading-tight">SigningController</span>**. Hệ thống sử dụng cơ chế đọc **Magic Bytes** để xem cấu trúc thật của Core File (Hex Header bắt đầu bằng `%PDF-` thì by-pass cơ chế converter của Word/Excel và coi thẳng đó là PDF). Đảm bảo File luôn lọt qua máy chủ ký tự động.

# 8.3. Lỗi Request OTP & Authentication (HTTP 400/401)

Dự án áp dụng logic ký bảo mật qua Session OTP sinh tự động. Lỗi thường phát sinh tại API `/api/sign/request-otp` và API ký.

**Hiện tượng:** Web/Portal trả về thông điệp lỗi HTTP status 400 Bad Request, hoặc "Phiên ký không hợp lệ". **Cách khắc phục:**

1. Khi gọi `/api/sign`, Client bắt buộc phải có thông tin Token phiên làm việc ở Header `Token-Signing`.
2. Dữ liệu Request OTP yêu cầu người dùng (`username`) và email được cấp từ `SecurityUtils` phải đúng cấu trúc. IT cần kiểm tra hệ thống tài khoản E-Office đã gửi User Context hợp lệ sang khối Ký số chưa (Nếu Header OAuth/JWT truyền qua sai `username`, Service sẽ ngắt lệnh).

# 8.4. Lỗi độ trễ Redis Cache (EJBCA Lookup Error)

**Hiện tượng:** Tài liệu ký bị pending quá lâu, timeout, hoặc hệ thống báo *"Người dùng không tồn tại"*. **Cách xử lý:**

1. Hệ thống dùng Redis để quản lý cache hàm `endEntityExists()`.
2. IT cần kiểm tra xem Container `kyso-redis` có đang sống và đáp trả lệnh ping không (`docker logs kyso-redis`).
3. Trong trường hợp người dùng trên CA vừa mới bị vô hiệu hóa hoặc thu hồi chứng chỉ `.p12`, việc kiểm tra cache bị "lỗi nhịp" với thực tế. Hệ thống `signing-web-service` đã xử lý bằng lệnh `signingService.revokeCache(username)` xóa ngay luồng cache chết trên Redis.
4. Môi trường Dev có thể thử lệnh `redis-cli flushall` để xóa sạch Redis phục vụ Test Fresh Data với máy chủ EJBCA.

---

*(Bản tài liệu "Signing Service Tân Cảng" được hoàn thành phục vụ công tác đào tạo và bàn giao Source Code. Mọi vấn đề về Security Endpoint hay Keys vui lòng liên hệ Admin System Tân Cảng).*