Tổng quan
econtractid hỗ trợ nhúng giao diện trực tiếp vào website của bên thứ ba thông qua <iframe>. Người dùng không cần rời khỏi hệ thống hiện tại mà vẫn có thể:
- Xem danh sách hồ sơ / hợp đồng
- Xem chi tiết và xem PDF hợp đồng
- Thực hiện ký số (ký đơn giản, ký ảnh, ký USB Token, ký Cloud HSM)
- Xử lý công việc liên quan đến hợp đồng
Phương thức này phù hợp cho các hệ thống muốn tích hợp nhanh giao diện
econtractid mà không cần phát triển lại UI.
Luồng hoạt động
Bước 1: Lấy Access Token
Có 2 cách để lấy accessToken từ hệ thống econtractid:
Đăng nhập bằng tài khoản người dùng (username + password):POST https://api.econtractid.vn/api/auth/login
Content-Type: application/json
{
"username": "user@example.com",
"password": "your_password"
}
Response thành công:{
"statusCode": 200,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600
}
}
| Trường | Kiểu | Mô tả |
|---|
username | string | Email hoặc tên đăng nhập |
password | string | Mật khẩu tài khoản |
Phù hợp khi hệ thống bên thứ ba quản lý trực tiếp thông tin đăng nhập của người dùng trên econtractid.
Đăng nhập phía server bằng Secret Key kết hợp số CCCD (Căn cước công dân) của người dùng. Phương thức này dành cho tích hợp server-to-server, không yêu cầu người dùng nhập mật khẩu.POST https://api.econtractid.vn/api/auth/login-server
Content-Type: application/json
{
"secretKey": "your_secret_key",
"cccd": "001234567890"
}
Response thành công:{
"statusCode": 200,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600
}
}
| Trường | Kiểu | Mô tả |
|---|
secretKey | string | Secret Key được cấp cho hệ thống tích hợp. Lấy tại Cài đặt → Tích hợp → API Keys |
cccd | string | Số Căn cước công dân của người dùng cần đăng nhập |
Phù hợp khi hệ thống bên thứ ba đã có thông tin CCCD của người dùng và muốn tự động đăng nhập mà không cần người dùng nhập tài khoản/mật khẩu econtractid.
Secret Key là thông tin nhạy cảm, chỉ nên gọi API này từ phía server (backend), tuyệt đối không để lộ Secret Key ở phía client (frontend/trình duyệt).
Access Token có hiệu lực 1 giờ. Khi token hết hạn, cần gọi API refresh
hoặc login lại để lấy token mới và cập nhật lại iframe.
Xem chi tiết về xác thực tại Xác thực & Phân quyền API.
Bước 2: Tạo URL nhúng
Tạo URL truy cập econtractid kèm accessToken dưới dạng query parameter at:
https://app.econtractid.com/{đường-dẫn}?at={accessToken}
Các đường dẫn phổ biến
| Đường dẫn | Mô tả |
|---|
/dashboard | Trang tổng quan |
/ho-so | Danh sách hồ sơ hợp đồng |
/ho-so/{id} | Chi tiết một hồ sơ cụ thể |
/xu-ly-cong-viec | Danh sách công việc cần xử lý |
/ky-so/{id} | Trang ký số hợp đồng |
Ví dụ URL đầy đủ:
https://app.econtractid.com/ho-so?at=eyJhbGciOiJIUzI1NiIs...
Để kiểm tra nhanh, bạn có thể đăng nhập hệ thống econtractid, lấy accessToken
từ DevTools (Application → localStorage), sau đó mở trình duyệt mới (hoặc cửa
sổ ẩn danh) và paste URL kèm accessToken để xác nhận hoạt động đúng.
Bước 3: Nhúng iframe vào website
HTML thuần
<iframe
id="econtract-frame"
src="https://app.econtractid.com/ho-so?at=YOUR_ACCESS_TOKEN"
width="100%"
height="800px"
frameborder="0"
style="border: 1px solid #ddd; border-radius: 8px; background: #fff;"
allow="clipboard-read; clipboard-write"
>
</iframe>
Angular
// component.ts
import { Component, OnInit } from "@angular/core";
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
@Component({
selector: "app-econtract-embed",
template: `
<iframe
id="econtract-frame"
[src]="econtractIframeSrc"
width="100%"
height="800px"
frameborder="0"
style="border: 1px solid #ddd; border-radius: 8px; background: #fff;"
allow="clipboard-read; clipboard-write"
>
</iframe>
`,
})
export class EcontractEmbedComponent implements OnInit {
econtractIframeSrc: SafeResourceUrl = "";
constructor(private sanitizer: DomSanitizer) {}
ngOnInit(): void {
const accessToken = "eyJhbGciOiJIUzI1NiIs..."; // Lấy từ API login
const baseUrl = "https://app.econtractid.com/ho-so";
const url = `${baseUrl}?at=${accessToken}`;
this.econtractIframeSrc =
this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
React
import React, { useState, useEffect } from "react";
function EcontractEmbed() {
const [iframeSrc, setIframeSrc] = useState("");
useEffect(() => {
// Gọi API login để lấy accessToken
async function getToken() {
const response = await fetch(
"https://api.econtractid.vn/api/auth/login",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "user@example.com",
password: "your_password",
}),
},
);
const data = await response.json();
const accessToken = data.data.accessToken;
setIframeSrc(`https://app.econtractid.com/ho-so?at=${accessToken}`);
}
getToken();
}, []);
if (!iframeSrc) return <div>Đang tải...</div>;
return (
<iframe
id="econtract-frame"
src={iframeSrc}
width="100%"
height="800px"
frameBorder="0"
style={{
border: "1px solid #ddd",
borderRadius: "8px",
background: "#fff",
}}
allow="clipboard-read; clipboard-write"
/>
);
}
export default EcontractEmbed;
Vue.js
<template>
<iframe
v-if="iframeSrc"
id="econtract-frame"
:src="iframeSrc"
width="100%"
height="800px"
frameborder="0"
style="border: 1px solid #ddd; border-radius: 8px; background: #fff;"
allow="clipboard-read; clipboard-write"
/>
<div v-else>Đang tải...</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const iframeSrc = ref("");
onMounted(async () => {
const response = await fetch("https://api.econtractid.vn/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "user@example.com",
password: "your_password",
}),
});
const data = await response.json();
const accessToken = data.data.accessToken;
iframeSrc.value = `https://app.econtractid.com/ho-so?at=${accessToken}`;
});
</script>
Xử lý sự cố
| Vấn đề | Nguyên nhân | Giải pháp |
|---|
| Iframe hiển thị trang login | Token hết hạn hoặc không hợp lệ | Kiểm tra lại token, gọi refresh hoặc login lại |
Lỗi Refused to display in a frame | Domain chưa được đăng ký | Liên hệ hỗ trợ để đăng ký domain |
| Iframe trắng trống | CSP chặn iframe | Thêm frame-src vào CSP của website |
| Không ký được bằng USB Token | Iframe chặn plugin | Sử dụng phương thức ký Cloud HSM hoặc ký ảnh thay thế |
| Token hết hạn liên tục | Không có cơ chế refresh | Triển khai auto-refresh token (xem mục Xử lý Token hết hạn) |
Hỗ trợ
Nếu gặp vấn đề khi tích hợp, liên hệ đội ngũ hỗ trợ: