From ba8f5b71df68d072e65f904a26b10c4092c24f93 Mon Sep 17 00:00:00 2001 From: jyu213 Date: Fri, 1 Dec 2023 15:01:43 +0800 Subject: [PATCH 1/2] feat: add auth doc --- .../asset-selector/getting-started.mdx | 4 + docs/frontend/asset-uploader/authorize.md | 112 ----------------- .../asset-uploader/getting-started.mdx | 2 + docs/frontend/common/_category_.json | 9 ++ .../authorize.md => common/authorize.mdx} | 48 +++++++- .../group-selector/getting-started.mdx | 2 + examples/encrypt/index.tsx | 113 ++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 6 + tailwind.config.js | 4 +- 10 files changed, 183 insertions(+), 118 deletions(-) delete mode 100644 docs/frontend/asset-uploader/authorize.md create mode 100644 docs/frontend/common/_category_.json rename docs/frontend/{asset-selector/authorize.md => common/authorize.mdx} (78%) create mode 100644 examples/encrypt/index.tsx diff --git a/docs/frontend/asset-selector/getting-started.mdx b/docs/frontend/asset-selector/getting-started.mdx index 98bfbd1..c79154c 100644 --- a/docs/frontend/asset-selector/getting-started.mdx +++ b/docs/frontend/asset-selector/getting-started.mdx @@ -3,8 +3,12 @@ sidebar_position: 2 title: 快速开始 --- +import Link from '@docusaurus/Link'; + 你需要将素材选择器的链接用 iframe 嵌入你的系统,你的代码和组件会基于[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)来进行通信交互数据。 +在开始接入前,你需要先完成 授权 + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/frontend/asset-uploader/authorize.md b/docs/frontend/asset-uploader/authorize.md deleted file mode 100644 index 8f1b0ff..0000000 --- a/docs/frontend/asset-uploader/authorize.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -sidebar_position: 3 ---- - -# 授权 - -向特赞申请:authUrl, aesKey, aesIv -SSO 认证链接格式:{authUrl}?aesUserInfo={经过 aesKey 加密的用户信息}&targetUrl={encodeURIComponent(认证成功重定向地址)},加密信息生成规则如下: - -```java -import com.alibaba.fastjson.JSONObject; -import org.apache.commons.codec.binary.Base64; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AES加密工具 - */ -public class AESUtilV2 { - private static final String KEY_ALGORITHM = "AES"; - // CBC mode - private static final String ENCRYPT_MODE_CBC = "AES/CBC/PKCS5Padding"; - - /** - * AES 加密操作 - * - * @param plainText 明文 - * @param key 密钥 - * @param iv 向量 - * @return 返回Base64转码后的加密数据 - */ - public static String encryptAndEncode(String plainText, String key, String iv) { - try { - byte[] bytePlainText = plainText.getBytes(StandardCharsets.UTF_8); - byte[] byteKey = key.getBytes(StandardCharsets.UTF_8); - byte[] byteIV = iv.getBytes(StandardCharsets.UTF_8); - - Cipher cipher = Cipher.getInstance(ENCRYPT_MODE_CBC);// 创建密码器 - IvParameterSpec ivParam = new IvParameterSpec(byteIV); - SecretKeySpec secretKey = new SecretKeySpec(byteKey, KEY_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParam);// 初始化为加密模式的密码器 - byte[] result = cipher.doFinal(bytePlainText);// 加密 - String encryptString = Base64.encodeBase64String(result); - return URLEncoder.encode(encryptString, "utf-8"); - } catch (Exception ex) { - Logger.getLogger(AESUtilV2.class.getName()).log(Level.SEVERE, null, ex); - } - - return null; - } - - /** - * AES 解密操作 - * - * @param ciphertext 密文 - * @param key 密钥 - * @param iv 向量 - * @return 明文 - */ - public static String decryptAndDecode(String ciphertext, String key, String iv) { - try { - ciphertext = URLDecoder.decode(ciphertext, StandardCharsets.UTF_8.name()); - byte[] byteKey = key.getBytes(StandardCharsets.UTF_8); - byte[] byteIV = iv.getBytes(StandardCharsets.UTF_8); - Cipher cipher = Cipher.getInstance(ENCRYPT_MODE_CBC); - IvParameterSpec ivParam = new IvParameterSpec(byteIV); - SecretKeySpec secretKey = new SecretKeySpec(byteKey, KEY_ALGORITHM); - //使用密钥、向量进行初始化,设置为解密模式 - cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParam); - //执行操作 - byte[] result = cipher.doFinal(Base64.decodeBase64(ciphertext)); - return new String(result, StandardCharsets.UTF_8); - } catch (Exception ex) { - Logger.getLogger(AESUtilV2.class.getName()).log(Level.SEVERE, null, ex); - } - - return null; - } - - public static void main(String[] args) { - JSONObject jo = new JSONObject(); - // 用户邮箱和手机号,二者必选其一 - jo.putIfAbsent("loginEmail", "wangfeng@tezign.com"); - jo.putIfAbsent("loginPhone", "15705273217"); - // 租户域名 - jo.putIfAbsent("domain", "vms-t13.tezign.com"); - // 加密时间,认证服务端会根据该时间戳进行失效校验 - jo.putIfAbsent("encryptTime", new Date()); - // 用户名,可选 - jo.putIfAbsent("username", "levi.wang"); - - // 加密秘钥和偏移向量,由特赞对接人员提供 - String aesKey = "1234567890abcdef"; - String aesIv = "1234567890abcdef"; - - String ss = jo.toString(); - String aa = encryptAndEncode(ss, aesKey, aesIv); - System.out.println("加密====== " + aa); - - String bb = decryptAndDecode(aa, aesKey, aesIv); - System.out.println("解密====== " + bb); - } -} -``` diff --git a/docs/frontend/asset-uploader/getting-started.mdx b/docs/frontend/asset-uploader/getting-started.mdx index 18c94fa..a2348cb 100644 --- a/docs/frontend/asset-uploader/getting-started.mdx +++ b/docs/frontend/asset-uploader/getting-started.mdx @@ -6,6 +6,8 @@ sidebar_position: 2 你需要将素材上传组件的链接用 iframe 嵌入你的系统,你的代码和素材上传组件会基于[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)来进行通信交互数据。 +在开始接入前,你需要先完成 授权 + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/docs/frontend/common/_category_.json b/docs/frontend/common/_category_.json new file mode 100644 index 0000000..69f1408 --- /dev/null +++ b/docs/frontend/common/_category_.json @@ -0,0 +1,9 @@ +{ + "label": "通用流程", + "position": 1, + "link": { + "type": "generated-index", + "slug": "/category/common", + "description": "xx" + } +} diff --git a/docs/frontend/asset-selector/authorize.md b/docs/frontend/common/authorize.mdx similarity index 78% rename from docs/frontend/asset-selector/authorize.md rename to docs/frontend/common/authorize.mdx index 8f1b0ff..89f3c3c 100644 --- a/docs/frontend/asset-selector/authorize.md +++ b/docs/frontend/common/authorize.mdx @@ -1,11 +1,41 @@ --- -sidebar_position: 3 +sidebar_position: 1 --- # 授权 -向特赞申请:authUrl, aesKey, aesIv -SSO 认证链接格式:{authUrl}?aesUserInfo={经过 aesKey 加密的用户信息}&targetUrl={encodeURIComponent(认证成功重定向地址)},加密信息生成规则如下: +通过 iframe 访问相关的开放组件,首先你需要进行授权,授权成功后,你才能访问到相关的开放组件。 + +## 授权流程 + +1. 向特赞申请:authUrl, aesKey, aesIv,并根据实际的业务场景,咨询使用的租户域名,邮箱/手机等信息。 +2. SSO 认证链接格式:`{authUrl}?aesUserInfo={encodeURIComponent(经过 aesKey 加密的用户信息)}&targetUrl={encodeURIComponent(认证成功重定向地址)}` + +加密算法: + +- AES. 数据填充方式: `AES/CBC/PKCS5Padding` + +加密字段信息,举例如下: + +```json +{ + "loginEmail": "test@demo.com", + "domain": "test.demo.com", + "encryptTime": 1701051555480 +} +``` + +> sso 的 url 参数需要进行 encodeURIComponent 处理 + +## Example + +加密信息示例代码如下: + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + ```java import com.alibaba.fastjson.JSONObject; @@ -49,7 +79,7 @@ public class AESUtilV2 { cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParam);// 初始化为加密模式的密码器 byte[] result = cipher.doFinal(bytePlainText);// 加密 String encryptString = Base64.encodeBase64String(result); - return URLEncoder.encode(encryptString, "utf-8"); + return encryptString; } catch (Exception ex) { Logger.getLogger(AESUtilV2.class.getName()).log(Level.SEVERE, null, ex); } @@ -110,3 +140,13 @@ public class AESUtilV2 { } } ``` + + + + + +## 验证 + +import EncryptComponent from '../../../examples/encrypt/index'; + + diff --git a/docs/frontend/group-selector/getting-started.mdx b/docs/frontend/group-selector/getting-started.mdx index 48c7bd6..96f2603 100644 --- a/docs/frontend/group-selector/getting-started.mdx +++ b/docs/frontend/group-selector/getting-started.mdx @@ -5,6 +5,8 @@ title: 快速开始 你需要将素材组选择器的链接用 iframe 嵌入你的系统,你的代码和组件会基于[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)来进行通信交互数据。 +在开始接入前,你需要先完成 授权 + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; diff --git a/examples/encrypt/index.tsx b/examples/encrypt/index.tsx new file mode 100644 index 0000000..6b023d2 --- /dev/null +++ b/examples/encrypt/index.tsx @@ -0,0 +1,113 @@ +import React, { useState } from 'react'; +// import crypto from 'crypto-browserify'; +const CryptoJS = require('crypto-js'); + +function encrypt(data, key, iv) { + // Convert the key and IV from UTF-8 strings to WordArrays + const keyBytes = CryptoJS.enc.Utf8.parse(key); + const ivBytes = CryptoJS.enc.Utf8.parse(iv); + + // Encrypt the data using AES-CBC with PKCS5Padding + const encrypted = CryptoJS.AES.encrypt(data, keyBytes, { + iv: ivBytes, + padding: CryptoJS.pad.Pkcs7, + mode: CryptoJS.mode.CBC, + }); + + // Return the encrypted data as a Base64-encoded string + return encrypted.toString(); +} + +function decrypt(data, key, iv) { + // Convert the key and IV from UTF-8 strings to WordArrays + const keyBytes = CryptoJS.enc.Utf8.parse(key); + const ivBytes = CryptoJS.enc.Utf8.parse(iv); + + // Decrypt the data using AES-CBC with PKCS5Padding + const decrypted = CryptoJS.AES.decrypt(data, keyBytes, { + iv: ivBytes, + padding: CryptoJS.pad.Pkcs7, + mode: CryptoJS.mode.CBC, + }); + + // Convert the decrypted data from a WordArray to a UTF-8 string + const decryptedData = decrypted.toString(CryptoJS.enc.Utf8); + + // Return the decrypted data + return decryptedData; +} + +export default function EncryptComponent() { + const [input, setInput] = useState(''); + const [output, setOutput] = useState(''); + const [key, setKey] = useState(''); + const [iv, setIV] = useState(''); + + const en = (input, key, iv) => { + if (!key || !iv || !input) { + return; + } + const encrypted = encrypt(input, key, iv); + console.log(encrypted); + setOutput(encrypted); + }; + const de = (output, key, iv) => { + if (!key || !iv || !output) { + return; + } + const decrypted = decrypt(output, key, iv); + console.log(decrypted); + setInput(decrypted); + }; + + return ( +
+

AES

+ +

+ Input Encryption
+ +

+

+ aesKey:{' '} + { + setKey(e.target.value); + en(input, e.target.value, iv); + }} + className="w-200 p-2 rounded-md border-gray-300 border-solid" + /> +

+

+ aesIv:{' '} + { + setIV(e.target.value); + en(input, key, e.target.value); + }} + className="w-200 p-2 rounded-md border-gray-300 border-solid" + /> +

+

+ Output Encryption
+ +

+
+ ); +} diff --git a/package.json b/package.json index 27cfc93..e426e55 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@docusaurus/theme-common": "2.4.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", + "crypto-js": "^4.2.0", "prism-react-renderer": "^1.3.5", "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e032e9f..3157ea2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,7 @@ specifiers: '@types/react-dom': ^17 autoprefixer: ^10.4.14 clsx: ^1.2.1 + crypto-js: ^4.2.0 husky: ^8.0.3 lint-staged: ^13.2.2 postcss: ^8.4.22 @@ -31,6 +32,7 @@ dependencies: '@docusaurus/theme-common': 2.4.1_njlomt5ggpdtwusgqgzwkzrpsa '@mdx-js/react': 1.6.22_react@17.0.2 clsx: 1.2.1 + crypto-js: 4.2.0 prism-react-renderer: 1.3.5_react@17.0.2 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 @@ -3569,6 +3571,10 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /crypto-js/4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + dev: false + /crypto-random-string/2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} diff --git a/tailwind.config.js b/tailwind.config.js index 0e95699..34de41b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,7 +1,7 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: ["class", '[data-theme="dark"]'], - content: ["./src/**/*.{tsx,jsx}"], + darkMode: ['class', '[data-theme="dark"]'], + content: ['./src/**/*.{tsx,jsx}', './examples/**/*.{tsx,jsx}'], theme: { extend: {}, }, From fca76e7914650a0ee7ac5032f403d201422b2257 Mon Sep 17 00:00:00 2001 From: jyu213 Date: Fri, 1 Dec 2023 16:29:24 +0800 Subject: [PATCH 2/2] fix: text errror --- .../2022-05-25-asset-selector-v1.2.0/index.md | 2 +- docs/frontend/asset-selector/config.md | 6 +-- .../asset-selector/events/component.md | 48 ++++++++++++++++++- .../frontend/asset-selector/events/confirm.md | 2 +- docs/frontend/asset-selector/events/index.md | 2 +- .../asset-selector/events/selection-change.md | 17 ------- .../asset-selector/getting-started.mdx | 14 +++--- docs/frontend/asset-selector/index.md | 6 ++- docs/frontend/asset-selector/ui.md | 2 +- docs/frontend/asset-uploader/events/cancel.md | 2 + .../frontend/asset-uploader/events/confirm.md | 2 +- docs/frontend/asset-uploader/events/index.md | 2 +- .../asset-uploader/events/transfer.md | 2 +- .../asset-uploader/getting-started.mdx | 10 ++-- docs/frontend/asset-uploader/index.md | 2 +- docs/frontend/asset-uploader/ui.md | 2 +- docs/frontend/common/authorize.mdx | 6 +-- docs/frontend/group-selector/events/index.md | 2 +- .../group-selector/getting-started.mdx | 8 +++- examples/encrypt/index.tsx | 2 - 20 files changed, 89 insertions(+), 50 deletions(-) delete mode 100644 docs/frontend/asset-selector/events/selection-change.md diff --git a/changelog/2022-05-25-asset-selector-v1.2.0/index.md b/changelog/2022-05-25-asset-selector-v1.2.0/index.md index d11f205..e853ab0 100644 --- a/changelog/2022-05-25-asset-selector-v1.2.0/index.md +++ b/changelog/2022-05-25-asset-selector-v1.2.0/index.md @@ -205,7 +205,7 @@ iframe.contentWindow.postMessage( { id: 'image', limit: 5 }, { id: 'audio', limit: 9, sizeLimit: 10 * Math.pow(1024, 2) }, ], - filterCode: 'open-component-search-001', + filterCode: 'open-component-search-003', formatLimit: 5, sizeLimit: 10 * Math.pow(1024, 2), // 只能选择<=10MB素材 }, diff --git a/docs/frontend/asset-selector/config.md b/docs/frontend/asset-selector/config.md index 9eec99f..ffaeada 100644 --- a/docs/frontend/asset-selector/config.md +++ b/docs/frontend/asset-selector/config.md @@ -61,7 +61,7 @@ iframe.contentWindow.postMessage( sizeLimit: 10 * 1024 ** 2, //只能选择<=10MB的音频 }, ], - filterCode: 'open-component-search-001', + filterCode: 'open-component-search-003', formatLimit: 5, sizeLimit: 10 * Math.pow(1024, 2), // 只能选择<=10MB素材 groupId: 123456, @@ -76,5 +76,5 @@ iframe.contentWindow.postMessage( - 支持将素材组内的素材全部添加到列表中。查询组内数量上限为 1000 - 关于选组添加的校验限制说明: -* 如果限制总数量或大小,未满足的情况下,整组素材将不被选择 -* 如果限制了具体格式数量或大小,只要存在未满足的情况下,整组素材将不被选择 + - 如果限制总数量或大小,未满足的情况下,整组素材将不被选择 + - 如果限制了具体格式数量或大小,只要存在未满足的情况下,整组素材将不被选择 diff --git a/docs/frontend/asset-selector/events/component.md b/docs/frontend/asset-selector/events/component.md index d705b37..6553664 100644 --- a/docs/frontend/asset-selector/events/component.md +++ b/docs/frontend/asset-selector/events/component.md @@ -4,7 +4,51 @@ sidebar_position: 5 # 组件事件 -## 数据结构 +选择器还支持其他相关的事件,来辅助接入方更好的控制选择器的行为。 + +## 选择更新 + +触发时机是用户选择素材更新的时候。 + +### 数据结构 + +```typescript +interface SelectionChangeEvent { + // 事件标识 + type: 'tezign-selector-selection-change'; + data: ConfirmData; // 同tezgin-selector-confirm-btn的数据结构(查看权限) +} +``` + +## 清空素材 + +清空用户所选素材 + +### 数据结构 + +```typescript +interface ClearEvent { + // 事件标识 + type: 'tezign-selector-clear'; +} +``` + +## 重置数据 + +重置整个 iframe 数据。重置内部包括用户所选素材、搜索关键字、筛选项等。 + +### 数据结构 + +```typescript +interface ResetEvent { + // 事件标识 + type: 'tezign-selector-reset'; +} +``` + +## 支持额外扩展底部操作组件栏 + +### 数据结构 ```typescript interface EventComponent { @@ -22,7 +66,7 @@ enum ECompType { } ``` -## 例子 +### 例子 ```javascript // 配置checkbox到底部操作栏 diff --git a/docs/frontend/asset-selector/events/confirm.md b/docs/frontend/asset-selector/events/confirm.md index f5e5dc1..338e1e9 100644 --- a/docs/frontend/asset-selector/events/confirm.md +++ b/docs/frontend/asset-selector/events/confirm.md @@ -4,7 +4,7 @@ sidebar_position: 4 # 确认按钮点击 -选择素材后,点击页面「确认」按钮,素材选择器会使用 postMessage 把所有选择的素材的对象数组在您的页面中返回,该响应数组包含 DAM 的所有资产信息。 +选择素材后,点击页面「确认」按钮,素材选择器会使用 `postMessage` 把所有选择的素材以对象数组在您的页面中返回,该响应数组包含 DAM 的相关资产信息。 ## 数据结构 diff --git a/docs/frontend/asset-selector/events/index.md b/docs/frontend/asset-selector/events/index.md index a2dcb82..632f58f 100644 --- a/docs/frontend/asset-selector/events/index.md +++ b/docs/frontend/asset-selector/events/index.md @@ -4,4 +4,4 @@ sidebar_position: 7 # 事件 -事件会通过`postMessage`来发送,接入方监听 Window 对象的`message`事件,按需处理相应的事件。 +事件会通过 `postMessage` 来发送,接入方监听 Window 对象的 `message` 事件,按需处理相应的事件。 diff --git a/docs/frontend/asset-selector/events/selection-change.md b/docs/frontend/asset-selector/events/selection-change.md deleted file mode 100644 index b3a0b78..0000000 --- a/docs/frontend/asset-selector/events/selection-change.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -sidebar_position: 5 ---- - -# 选择更新 - -触发时机是用户选择素材更新的时候。 - -## 数据结构 - -```typescript -interface SelectionChangeEvent { - // 事件标识 - type: 'tezign-selector-selection-change'; - data: ConfirmData; // 同tezgin-selector-confirm-btn的数据结构(查看权限) -} -``` diff --git a/docs/frontend/asset-selector/getting-started.mdx b/docs/frontend/asset-selector/getting-started.mdx index c79154c..880e81c 100644 --- a/docs/frontend/asset-selector/getting-started.mdx +++ b/docs/frontend/asset-selector/getting-started.mdx @@ -5,9 +5,11 @@ title: 快速开始 import Link from '@docusaurus/Link'; -你需要将素材选择器的链接用 iframe 嵌入你的系统,你的代码和组件会基于[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)来进行通信交互数据。 +在开始接入前,你需要先完成 授权。 -在开始接入前,你需要先完成 授权 +素材选择器的链接通过 iframe 嵌入你的系统,你的代码和组件会基于 [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) 来进行通信交互数据。 + +素材选择器链接是: `{domain}/dam_enterprise/material_selector`。 其中 `domain` 为客户内容中台的域名。 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -20,14 +22,14 @@ import TabItem from '@theme/TabItem'; - 素材选择器父页面 + 素材上传父页面