@cqsjjb/base-platform-sdk
v1.0.3
Published
Base platform iframe SDK (open auth, SM2 config)
Downloads
483
Readme
@cqsjjb/base-platform-sdk
在业务页面中嵌入基座平台的浏览器端 SDK:通过开放账号接口完成用户鉴权(含 SM2 加密配置),并在容器内挂载带登录态参数的 iframe;新用户会先出现授权确认,再继续创建账号。
特性
- ESM:适用于 Vite、Webpack 5、Create React App(配合配置)等现代打包工具,或原生
<script type="module">。 - TypeScript:提供类型声明,便于在 TS 项目中获得提示。
- 开放账号流程:
getUserInfo→(无用户数据则)授权弹窗 →createUser→ 拼接 iframe 地址并挂载。 - 事件回调:鉴权各阶段、授权确认/取消、挂载/卸载均可订阅。
- 依赖:
sm-crypto会随本包安装,用于对config做 SM2 加密,无需再单独引入 CDN 版本。
环境要求
- 浏览器(需
fetch、document、iframe 等 DOM API)。 - 建议使用 HTTPS 或与接口同策略的部署环境;跨域与 Cookie 策略由后端与浏览器共同决定。
安装
npm install @cqsjjb/base-platform-sdk安装后请确保工程能解析 ESM(主流前端脚手架默认支持)。不要用 file:// 直接打开本地 HTML,否则 ES 模块可能被浏览器拦截;本地预览请使用 dev server(如 npm run dev)或 npx serve 等。
使用示例
以下示例中,platformOrigin、appkey、config、host 请替换为与后端约定的实际值(platformOrigin 为基座平台根地址,开放接口与 iframe 均同源)。
React(函数组件 + Hooks)
import { useEffect, useRef } from 'react';
import { createPlatform } from '@cqsjjb/base-platform-sdk';
import type { Platform } from '@cqsjjb/base-platform-sdk';
export function BasePlatformEmbed() {
const containerRef = useRef<HTMLDivElement>(null);
const platformRef = useRef<Platform | null>(null);
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const platform = createPlatform({
platformOrigin: 'https://你的基座平台域名',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
// 其余字段与后端约定一致
},
host: typeof window !== 'undefined' ? window.location.origin : '',
});
platform.on('mount', () => {
console.log('iframe 已挂载');
});
platform.on('getUserInfo:error', (_p, detail) => {
console.error('获取用户信息失败', detail?.err);
});
platform.mount(el, {
width: '100%',
height: '600px',
style: { border: 'none' },
});
platformRef.current = platform;
return () => {
platform.unmount();
platformRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ width: '100%', minHeight: 400 }} />;
}要点:
- 用
ref拿到挂载容器,在useEffect里调用mount,避免重复创建实例时可把createPlatform放进 effect 或配合useMemo/useRef存实例。 - 在 effect 清理函数里调用
platform.unmount(),防止路由切换或组件卸载后残留 iframe 与监听。
Vue 3(<script setup>)
<template>
<div ref="containerRef" class="embed-wrap"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { createPlatform } from '@cqsjjb/base-platform-sdk';
import type { Platform } from '@cqsjjb/base-platform-sdk';
const containerRef = ref<HTMLDivElement | null>(null);
let platform: Platform | null = null;
onMounted(() => {
const el = containerRef.value;
if (!el) return;
platform = createPlatform({
platformOrigin: 'https://你的基座平台域名',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
},
host: typeof window !== 'undefined' ? window.location.origin : '',
});
platform.on('mount', () => {
console.log('iframe 已挂载');
});
platform.on('getUserInfo:error', (_p, detail) => {
console.error('获取用户信息失败', detail?.err);
});
platform.mount(el, {
width: '100%',
height: '600px',
style: { border: 'none' },
});
});
onBeforeUnmount(() => {
platform?.unmount();
platform = null;
});
</script>
<style scoped>
.embed-wrap {
width: 100%;
min-height: 400px;
}
</style>要点:
- 在
onMounted中执行mount,此时模板已渲染,ref已指向 DOM。 - 在
onBeforeUnmount中调用unmount(),与页面或组件生命周期对齐。
传统 HTML(原生 ES Module)
页面需通过 HTTP/HTTPS 访问(本地可用任意静态服务)。在页面中增加容器,并用 type="module" 的脚本从 node_modules 引入(路径按实际安装位置调整,打包到静态资源后也可用相对路径)。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>基座嵌入示例</title>
</head>
<body>
<div id="embed-root" style="width:100%;height:600px;border:1px solid #ccc;"></div>
<script type="module">
import { createPlatform } from './node_modules/@cqsjjb/base-platform-sdk/dist/index.js';
const container = document.getElementById('embed-root');
if (!container) throw new Error('找不到容器');
const platform = createPlatform({
platformOrigin: 'https://你的基座平台域名',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
},
host: window.location.origin,
});
platform.on('mount', () => console.log('iframe 已挂载'));
platform.on('getUserInfo:error', (_p, d) => console.error(d?.err));
platform.mount(container, {
width: '100%',
height: '100%',
style: { border: 'none' },
});
// 若需要在离开页面前卸载,可绑定 beforeunload 或你自己的导航逻辑:
// window.addEventListener('beforeunload', () => platform.unmount());
</script>
</body>
</html>若使用 Vite / Webpack 等多文件打包,通常不写死 node_modules 路径,而是在入口 JS 里写 import { createPlatform } from '@cqsjjb/base-platform-sdk',由打包器解析,再引入打包后的单文件脚本。
API 说明
createPlatform(options: PlatformOptions): Platform
创建平台实例。
| 字段 | 类型 | 说明 |
|------|------|------|
| platformOrigin | string | 必填。基座平台根地址(与开放账号接口、iframe 嵌入页同源),如 https://platform.example.com。末尾 / 可写可不写,SDK 会规范化。 |
| appkey | string | 必填。开放应用 appkey。 |
| sm2PublicKeyDerHex | string | 必填。SM2 公钥的 X.509 DER 十六进制串(与后端解密用私钥对应),用于加密 config。 |
| config | Record<string, unknown> | 可选。业务配置,将 JSON 序列化后经 SM2 加密 传给开放接口(字段名与后端约定一致)。 |
| host | string | 可选。请求体中的 host,一般填当前业务站点或后端认可的来源地址。 |
platform.mount(container, options?)
将 SDK 挂到 一个 DOM 容器上,内部会异步请求开放接口并在成功后插入 iframe。
参数
container:HTMLElement | null。一般为div等块级容器;为null时会在控制台报错并中止。options:MountOptions,可选:
| 字段 | 类型 | 说明 |
|------|------|------|
| style | Record<string, string> | 应用到 iframe 的 CSS 行内样式(如 border: 'none')。 |
| width | string | iframe 宽度,如 '100%'、'800px'。 |
| height | string | iframe 高度。 |
| attrs | Record<string, string> | 额外 HTML 属性(如 id、title)。 |
流程概要
- 展示「正在获取用户信息…」Loading。
- 调用
getUserInfo;失败则触发getUserInfo:error并结束。 - 若返回中 没有用户数据(
!res.data):关闭 Loading → 展示 授权确认(确认 / 取消)。- 确认:触发
auth:confirm,再 Loading「正在创建用户…」,调用createUser。 - 取消:在容器内展示「您已取消授权」文案,触发
auth:cancel,不再创建用户、不挂 iframe。
- 确认:触发
- 若有用户数据或
createUser成功拿到data:根据data拼接 iframe URL,插入iframe,mounted = true,触发mount。
platform.unmount()
卸载 iframe 并清空与本次挂载相关的内部状态;触发 unmount 事件。若当前未成功挂载 iframe,会在控制台提示错误。
实例属性(赋值即更新 iframe)
在 iframe 已存在 时,以下 setter 会同步到 DOM。
| 属性 | 说明 |
|------|------|
| platform.width | 字符串,如 '100%'。 |
| platform.height | 字符串。 |
| platform.style | 行内样式对象。 |
| platform.attrs | HTML 属性对象。 |
buildPlatformIframeSrc(data, platformOrigin): string
根据开放接口返回的 用户态数据 生成嵌入页 URL(与 SDK 内部挂载 iframe 时使用的规则一致)。第二参数可与 createPlatform 时一致,或直接传已有实例的 platform.platformOrigin。适用于需要自行打开新窗口或预校验 URL 的场景。
参数 data 至少可能包含:token、clientId、orgId、accessTicket(均可能为空,会参与 query 编码)。
normalizePlatformOrigin(origin): string
去掉首尾空白与末尾 /,与 SDK 内部拼接开放接口、iframe 地址时的规范化规则一致;若你在配置中心存的是带尾斜杠的 URL,可先经此函数再传入 platformOrigin(也可直接传入,构造函数内会再次规范化)。
事件
使用 platform.on(eventName, callback) 订阅。回调签名为 (platform, detail?)。
| 事件名 | 触发时机 | detail 大致内容 |
|--------|----------|-------------------|
| getUserInfo:start | 即将请求 getUserInfo | { authOpts } |
| getUserInfo:success | getUserInfo HTTP 成功且已解析 JSON | { res, authOpts } |
| getUserInfo:error | getUserInfo 抛错或 HTTP 非 2xx | { err, authOpts } |
| auth:confirm | 用户点击「确认授权」后、请求 createUser 前 | { authOpts } |
| auth:cancel | 用户点击「取消」 | { authOpts } |
| createUser:start | 即将请求 createUser | { authOpts } |
| createUser:success | createUser 成功 | { res1, authOpts } |
| createUser:error | createUser 失败 | { err, authOpts } |
| mount | iframe 已插入容器并完成绑定 | 无额外载荷(回调第一个参数仍为 platform) |
| unmount | 调用 unmount() 并完成清理 | 无额外载荷 |
使用 platform.off(eventName) 可移除对应监听。
TypeScript
包导出类型包括:PlatformOptions、MountOptions、AuthOpts、PlatformUserData、OpenAccountEnvelope 等。
import {
createPlatform,
buildPlatformIframeSrc,
normalizePlatformOrigin,
type PlatformOptions,
} from '@cqsjjb/base-platform-sdk';
const origin = normalizePlatformOrigin('https://platform.example.com/');
const url = buildPlatformIframeSrc(userData, origin);与后端约定
platformOrigin决定开放账号接口与 iframe 的基址,须与当前环境基座部署地址一致(测试 / 生产分别配置)。config字段须与后端解密、验签规则一致(SM2 加密由本包在浏览器侧完成)。- 若贵司接口在 HTTP 层之外还有业务错误码约定,请在业务代码中根据返回体自行处理(例如统一提示)。
常见问题
1. 页面里 import 报错 / 模块找不到
请通过 开发服务器或静态站点 访问页面,不要使用 file:// 打开含 ES Module 的 HTML。
2. 安装后没有类型提示
确认已正确安装依赖,且 IDE 使用的是包内的类型入口(由 package.json 的 "types" 字段指定)。
3. 新用户一直停在 Loading
检查网络、开放接口是否可达,以及 platformOrigin / appkey / config / host 是否与当前环境一致。
4. 授权成功但无法显示 这可能是跨域问题导致,需要联系技术人员处理。
开源协议
ISC(见发布包内 package.json 的 license 字段)。
