@arcblock/did-connect-react 3.1.40 → 3.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aigne/doc-smith/config.yaml +83 -0
- package/.aigne/doc-smith/output/structure-plan.json +197 -0
- package/.aigne/doc-smith/upload-cache.yaml +168 -0
- package/docs/_sidebar.md +18 -0
- package/docs/advanced-authentication-methods.ja.md +261 -0
- package/docs/advanced-authentication-methods.md +261 -0
- package/docs/advanced-authentication-methods.zh-TW.md +261 -0
- package/docs/advanced-authentication-methods.zh.md +261 -0
- package/docs/advanced-utilities.ja.md +132 -0
- package/docs/advanced-utilities.md +132 -0
- package/docs/advanced-utilities.zh-TW.md +132 -0
- package/docs/advanced-utilities.zh.md +132 -0
- package/docs/advanced.ja.md +95 -0
- package/docs/advanced.md +95 -0
- package/docs/advanced.zh-TW.md +95 -0
- package/docs/advanced.zh.md +95 -0
- package/docs/api-reference.ja.md +178 -0
- package/docs/api-reference.md +178 -0
- package/docs/api-reference.zh-TW.md +178 -0
- package/docs/api-reference.zh.md +178 -0
- package/docs/core-components-did-connect.ja.md +214 -0
- package/docs/core-components-did-connect.md +213 -0
- package/docs/core-components-did-connect.zh-TW.md +214 -0
- package/docs/core-components-did-connect.zh.md +213 -0
- package/docs/core-components-session-provider.ja.md +239 -0
- package/docs/core-components-session-provider.md +239 -0
- package/docs/core-components-session-provider.zh-TW.md +239 -0
- package/docs/core-components-session-provider.zh.md +239 -0
- package/docs/core-components.ja.md +16 -0
- package/docs/core-components.md +16 -0
- package/docs/core-components.zh-TW.md +16 -0
- package/docs/core-components.zh.md +16 -0
- package/docs/getting-started.ja.md +138 -0
- package/docs/getting-started.md +138 -0
- package/docs/getting-started.zh-TW.md +138 -0
- package/docs/getting-started.zh.md +138 -0
- package/docs/hooks-use-connect.ja.md +214 -0
- package/docs/hooks-use-connect.md +214 -0
- package/docs/hooks-use-connect.zh-TW.md +214 -0
- package/docs/hooks-use-connect.zh.md +214 -0
- package/docs/hooks-use-did.ja.md +107 -0
- package/docs/hooks-use-did.md +107 -0
- package/docs/hooks-use-did.zh-TW.md +107 -0
- package/docs/hooks-use-did.zh.md +107 -0
- package/docs/hooks-use-oauth-passkey.ja.md +188 -0
- package/docs/hooks-use-oauth-passkey.md +188 -0
- package/docs/hooks-use-oauth-passkey.zh-TW.md +188 -0
- package/docs/hooks-use-oauth-passkey.zh.md +188 -0
- package/docs/hooks.ja.md +23 -0
- package/docs/hooks.md +23 -0
- package/docs/hooks.zh-TW.md +23 -0
- package/docs/hooks.zh.md +23 -0
- package/docs/overview.ja.md +159 -0
- package/docs/overview.md +159 -0
- package/docs/overview.zh-TW.md +159 -0
- package/docs/overview.zh.md +160 -0
- package/docs/ui-components-address.ja.md +121 -0
- package/docs/ui-components-address.md +121 -0
- package/docs/ui-components-address.zh-TW.md +121 -0
- package/docs/ui-components-address.zh.md +121 -0
- package/docs/ui-components-avatar.ja.md +65 -0
- package/docs/ui-components-avatar.md +65 -0
- package/docs/ui-components-avatar.zh-TW.md +65 -0
- package/docs/ui-components-avatar.zh.md +65 -0
- package/docs/ui-components-button.ja.md +99 -0
- package/docs/ui-components-button.md +99 -0
- package/docs/ui-components-button.zh-TW.md +99 -0
- package/docs/ui-components-button.zh.md +99 -0
- package/docs/ui-components-logo.ja.md +52 -0
- package/docs/ui-components-logo.md +52 -0
- package/docs/ui-components-logo.zh-TW.md +52 -0
- package/docs/ui-components-logo.zh.md +52 -0
- package/docs/ui-components.ja.md +57 -0
- package/docs/ui-components.md +57 -0
- package/docs/ui-components.zh-TW.md +57 -0
- package/docs/ui-components.zh.md +57 -0
- package/glossary.md +1 -0
- package/lib/package.json.js +1 -1
- package/package.json +5 -5
- package/src/Session/hooks/use-federated.js +3 -0
- package/src/Session/libs/federated.js +3 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# 驗證方法
|
|
2
|
+
|
|
3
|
+
雖然 DID 錢包是主要且最安全的驗證方法,但 `@arcblock/did-connect-react` 仍為多種替代登入方法提供了強大的支援,以提供靈活性並滿足不同使用者的偏好。本節詳細介紹如何將 OAuth (社群登入)、Passkeys (無密碼驗證) 和统一登录站点群登入整合到您的應用程式中。
|
|
4
|
+
|
|
5
|
+
這些方法透過特定的 React Context Providers 啟用,並透過相應的 hooks 存取,這些 hooks 應巢狀嵌套在主 `SessionProvider` 中。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## OAuth (社群登入)
|
|
10
|
+
|
|
11
|
+
整合 Google、GitHub 或 Apple 等熱門社群登入供應商,讓使用者能用現有帳號登入。此功能由 `OAuthProvider` 和 `useOAuth` hook 管理。
|
|
12
|
+
|
|
13
|
+
### 1. 使用 `OAuthProvider` 設定
|
|
14
|
+
|
|
15
|
+
若要啟用 OAuth 功能,請用 `OAuthProvider` 包裹您的元件樹。通常會將其放置在 `SessionProvider` 內部。
|
|
16
|
+
|
|
17
|
+
```jsx OAuthProvider Setup icon=logos:react
|
|
18
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
19
|
+
import { OAuthProvider } from '@arcblock/did-connect-react/lib/OAuth';
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
return (
|
|
23
|
+
<SessionProvider>
|
|
24
|
+
<OAuthProvider
|
|
25
|
+
onBindOAuth={(provider) => console.log(`${provider.provider} 已綁定!`)}
|
|
26
|
+
onUnbindOAuth={(account) => console.log(`${account.provider} 已解除綁定!`)}>
|
|
27
|
+
{/* 您的應用程式元件 */}
|
|
28
|
+
</OAuthProvider>
|
|
29
|
+
</SessionProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**`OAuthProvider` 的 Props**
|
|
35
|
+
|
|
36
|
+
<x-field-group>
|
|
37
|
+
<x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="將有權存取 OAuth context 的子元件。"></x-field>
|
|
38
|
+
<x-field data-name="locale" data-type="string" data-default="en" data-desc="用於 UI 訊息和提示的語言。"></x-field>
|
|
39
|
+
<x-field data-name="onBindOAuth" data-type="function" data-desc="使用者成功綁定 OAuth 帳號後觸發的回呼函式。"></x-field>
|
|
40
|
+
<x-field data-name="onUnbindOAuth" data-type="function" data-desc="使用者成功解除綁定 OAuth 帳號後觸發的回呼函式。"></x-field>
|
|
41
|
+
<x-field data-name="onSwitchPassport" data-type="function" data-desc="使用者切換 passport 後觸發的回呼函式。"></x-field>
|
|
42
|
+
<x-field data-name="session" data-type="object" data-desc="目前的使用者 session 物件,passport 切換 UI 需要。"></x-field>
|
|
43
|
+
</x-field-group>
|
|
44
|
+
|
|
45
|
+
### 2. 使用 `useOAuth` Hook
|
|
46
|
+
|
|
47
|
+
`useOAuth` hook 提供了與 OAuth 驗證流程互動的函式。
|
|
48
|
+
|
|
49
|
+
```jsx useOAuth Hook icon=logos:react
|
|
50
|
+
import { useOAuth } from '@arcblock/did-connect-react/lib/OAuth';
|
|
51
|
+
|
|
52
|
+
function SocialLoginButtons() {
|
|
53
|
+
const { loginOAuth, getOAuthConfigList, bindAuthLoading } = useOAuth();
|
|
54
|
+
const [providers, setProviders] = React.useState([]);
|
|
55
|
+
|
|
56
|
+
React.useEffect(() => {
|
|
57
|
+
getOAuthConfigList().then(setProviders);
|
|
58
|
+
}, [getOAuthConfigList]);
|
|
59
|
+
|
|
60
|
+
const handleLogin = async (provider) => {
|
|
61
|
+
try {
|
|
62
|
+
const result = await loginOAuth({ provider: provider.provider });
|
|
63
|
+
console.log('登入成功:', result);
|
|
64
|
+
// 處理登入結果,例如更新 session
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('登入失敗:', error.message);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if (providers.length === 0) {
|
|
71
|
+
return <p>未設定第三方登入方式。</p>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div>
|
|
76
|
+
{providers.map((p) => (
|
|
77
|
+
<button key={p.provider} onClick={() => handleLogin(p)} disabled={bindAuthLoading}>
|
|
78
|
+
使用 {p.provider} 登入
|
|
79
|
+
</button>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 核心函式
|
|
87
|
+
|
|
88
|
+
- **`loginOAuth({ provider }, { action, ... })`**: 為特定供應商啟動登入流程。將會開啟一個彈出視窗供使用者驗證。
|
|
89
|
+
- **`bindOAuth({ session, oauthItem })`**: 將一個新的社群帳號綁定到目前登入的使用者。
|
|
90
|
+
- **`unbindOAuth({ session, connectedAccount })`**: 從目前使用者解除綁定一個社群帳號。
|
|
91
|
+
- **`getOAuthConfigList()`**: 非同步地取得在 Blocklet 設定中設定的已啟用 OAuth 供應商列表。
|
|
92
|
+
- **`switchOAuthPassport(user)`**: 開啟一個對話方塊,用於在與同一 OAuth 身分相關聯的不同使用者帳號 (passports) 之間切換。
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Passkeys (無密碼)
|
|
97
|
+
|
|
98
|
+
使用基於 WebAuthn 標準的 Passkeys,啟用現代、安全且無密碼的驗證。這讓使用者可以使用生物辨識 (指紋、臉部 ID)、裝置 PIN 碼或安全金鑰登入。
|
|
99
|
+
|
|
100
|
+
### 1. 使用 `PasskeyProvider` 設定
|
|
101
|
+
|
|
102
|
+
使用 `PasskeyProvider` 包裹您的應用程式以啟用 Passkey 功能。
|
|
103
|
+
|
|
104
|
+
```jsx PasskeyProvider Setup icon=logos:react
|
|
105
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
106
|
+
import { PasskeyProvider } from '@arcblock/did-connect-react/lib/Passkey';
|
|
107
|
+
|
|
108
|
+
function App() {
|
|
109
|
+
return (
|
|
110
|
+
<SessionProvider>
|
|
111
|
+
<PasskeyProvider
|
|
112
|
+
onAddPasskey={(result) => console.log('Passkey 已新增!', result)}
|
|
113
|
+
onRemovePasskey={(result) => console.log('Passkey 已移除!', result)}>
|
|
114
|
+
{/* 您的應用程式元件 */}
|
|
115
|
+
</PasskeyProvider>
|
|
116
|
+
</SessionProvider>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**`PasskeyProvider` 的 Props**
|
|
122
|
+
|
|
123
|
+
<x-field-group>
|
|
124
|
+
<x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="將有權存取 Passkey context 的子元件。"></x-field>
|
|
125
|
+
<x-field data-name="locale" data-type="string" data-default="en" data-desc="用於 UI 訊息和提示的語言。"></x-field>
|
|
126
|
+
<x-field data-name="onAddPasskey" data-type="function" data-desc="使用者成功新增 Passkey 後觸發的回呼函式。"></x-field>
|
|
127
|
+
<x-field data-name="onRemovePasskey" data-type="function" data-desc="使用者成功移除 Passkey 後觸發的回呼函式。"></x-field>
|
|
128
|
+
<x-field data-name="onSwitchPassport" data-type="function" data-desc="使用者切換 passport 後觸發的回呼函式。"></x-field>
|
|
129
|
+
<x-field data-name="session" data-type="object" data-desc="目前的使用者 session 物件,passport 切換 UI 需要。"></x-field>
|
|
130
|
+
</x-field-group>
|
|
131
|
+
|
|
132
|
+
### 2. 使用 `usePasskey` Hook
|
|
133
|
+
|
|
134
|
+
`usePasskey` hook 提供了 Passkey 註冊和驗證所需的所有函式。
|
|
135
|
+
|
|
136
|
+
```jsx usePasskey Hook icon=logos:react
|
|
137
|
+
import { usePasskey } from '@arcblock/did-connect-react/lib/Passkey';
|
|
138
|
+
import { useSession } from '@arcblock/did-connect-react';
|
|
139
|
+
|
|
140
|
+
function PasskeyAuth() {
|
|
141
|
+
const { loginPasskey, connectPasskey, connecting } = usePasskey();
|
|
142
|
+
const { session } = useSession();
|
|
143
|
+
|
|
144
|
+
const handleLogin = async () => {
|
|
145
|
+
try {
|
|
146
|
+
const result = await loginPasskey();
|
|
147
|
+
console.log('Passkey 登入成功:', result);
|
|
148
|
+
// 處理登入結果
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error('Passkey 登入失敗:', error.message);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleConnect = async () => {
|
|
155
|
+
// 這應該在使用者已經登入時呼叫
|
|
156
|
+
// 並且想要在他們的個人資料設定中新增一個 passkey。
|
|
157
|
+
if (!session.user) {
|
|
158
|
+
alert('您必須登入才能新增 passkey。');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
await connectPasskey();
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error('連接 passkey 失敗:', error.message);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div>
|
|
170
|
+
<button onClick={handleLogin}>使用 Passkey 登入</button>
|
|
171
|
+
{session.user && (
|
|
172
|
+
<button onClick={handleConnect} disabled={connecting}>
|
|
173
|
+
{connecting ? '連接中...' : '新增 Passkey'}
|
|
174
|
+
</button>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 核心函式
|
|
182
|
+
- **`loginPasskey({ action, ... })`**: 啟動 Passkey 驗證流程 (也稱為 assertion)。這用於登入現有使用者。
|
|
183
|
+
- **`connectPasskey(extraParams)`**: 一個高階函式,用於建立一個新的 Passkey 並將其綁定到目前使用者的帳號。它處理完整的註冊儀式。
|
|
184
|
+
- **`disconnectPasskey({ session, connectedAccount })`**: 在成功驗證後,從目前使用者的帳號中移除一個 Passkey。
|
|
185
|
+
- **`createPasskey(params)`**: 啟動 WebAuthn 註冊過程的較低階函式。`connectPasskey` 在內部使用此函式。
|
|
186
|
+
- **`verifyPasskey(params)`**: 啟動 WebAuthn 驗證過程的較低階函式。`loginPasskey` 和 `disconnectPasskey` 在內部使用此函式。
|
|
187
|
+
- **`switchPassport(user)`**: 開啟一個對話方塊,用於在可能共享 Passkeys 的不同使用者帳號 (passports) 之間切換。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 统一登录站点群登入
|
|
192
|
+
|
|
193
|
+
统一登录站点群登入允許一組關聯的 Blocklet 應用程式 (一個「统一登录站点群」) 共享單一登入 session。當使用者登入指定的「主」站點時,他們可以在任何「成員」站點上自動進行驗證,無需再次登入。
|
|
194
|
+
|
|
195
|
+
### 1. 概念與設定
|
|
196
|
+
|
|
197
|
+
此功能依賴於您 Blocklet 設定中的主從站點設定。需要 `FederatedProvider` 元件來處理此功能在現代瀏覽器中運作所需的跨網域通訊,特別是用於管理第三方 cookie 的存取。
|
|
198
|
+
|
|
199
|
+
與其他 provider 一樣,`FederatedProvider` 應包含在您的元件樹中,通常位於 `SessionProvider` 內部。
|
|
200
|
+
|
|
201
|
+
```jsx FederatedProvider Setup icon=logos:react
|
|
202
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
203
|
+
import { FederatedProvider } from '@arcblock/did-connect-react/lib/Federated';
|
|
204
|
+
|
|
205
|
+
function App() {
|
|
206
|
+
return (
|
|
207
|
+
<SessionProvider>
|
|
208
|
+
<FederatedProvider>
|
|
209
|
+
{/* 您的應用程式元件 */}
|
|
210
|
+
</FederatedProvider>
|
|
211
|
+
</SessionProvider>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 2. 使用方法
|
|
217
|
+
|
|
218
|
+
统一登录站点群登入邏輯直接整合到 session 管理中。您可以使用 `useSession` 回傳的 `session` 物件上的 `loginFederated` 函式來觸發它。
|
|
219
|
+
|
|
220
|
+
`loginFederated` 支援兩種模式:
|
|
221
|
+
- **`auto`**: 如果使用者在主站點上有活動的 session,則嘗試靜默登入使用者。這非常適合在頁面載入時進行檢查。
|
|
222
|
+
- **`manual`**: 啟動標準的 DID Connect 登入流程。成功登入後,它也會與主站點建立统一登录站点群 session。
|
|
223
|
+
|
|
224
|
+
```jsx Federated Login Example icon=logos:react
|
|
225
|
+
import { useSession } from '@arcblock/did-connect-react';
|
|
226
|
+
import React from 'react';
|
|
227
|
+
|
|
228
|
+
function FederatedLogin() {
|
|
229
|
+
const { session } = useSession();
|
|
230
|
+
const { federatedEnabled, loginFederated } = session;
|
|
231
|
+
|
|
232
|
+
// 在元件掛載時嘗試自動登入
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
if (federatedEnabled) {
|
|
235
|
+
loginFederated((err) => {
|
|
236
|
+
if (err) {
|
|
237
|
+
console.warn('自動统一登录站点群登入失敗:', err);
|
|
238
|
+
} else {
|
|
239
|
+
console.log('自動统一登录站点群登入成功!');
|
|
240
|
+
}
|
|
241
|
+
}, { mode: 'auto' });
|
|
242
|
+
}
|
|
243
|
+
}, [federatedEnabled, loginFederated]);
|
|
244
|
+
|
|
245
|
+
const handleManualLogin = () => {
|
|
246
|
+
loginFederated((err) => {
|
|
247
|
+
if (err) console.error('手動统一登录站点群登入失敗:', err);
|
|
248
|
+
}, { mode: 'manual' });
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
if (!federatedEnabled) {
|
|
252
|
+
return <p>未啟用统一登录站点群登入。</p>;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<button onClick={handleManualLogin}>
|
|
257
|
+
使用主站點帳號登入
|
|
258
|
+
</button>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# 身份验证方法
|
|
2
|
+
|
|
3
|
+
`DID Wallet` 是主要且最安全的身份验证方法,但 `@arcblock/did-connect-react` 也为多种替代登录方法提供了强大的支持,以提供灵活性并满足不同用户的偏好。本节详细介绍如何将 OAuth(社交登录)、Passkeys(无密码身份验证)和统一登录集成到您的应用程序中。
|
|
4
|
+
|
|
5
|
+
这些方法通过特定的 React Context Provider 启用,并通过相应的 Hook 进行访问,它们应嵌套在主 `SessionProvider` 内部。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## OAuth(社交登录)
|
|
10
|
+
|
|
11
|
+
集成 Google、GitHub 或 Apple 等流行的社交登录提供商,允许用户使用其现有帐户登录。此功能由 `OAuthProvider` 和 `useOAuth` Hook 管理。
|
|
12
|
+
|
|
13
|
+
### 1. 使用 OAuthProvider 进行设置
|
|
14
|
+
|
|
15
|
+
要启用 OAuth 功能,请使用 `OAuthProvider` 包裹您的组件树。通常将其放置在 `SessionProvider` 内部。
|
|
16
|
+
|
|
17
|
+
```jsx OAuthProvider Setup icon=logos:react
|
|
18
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
19
|
+
import { OAuthProvider } from '@arcblock/did-connect-react/lib/OAuth';
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
return (
|
|
23
|
+
<SessionProvider>
|
|
24
|
+
<OAuthProvider
|
|
25
|
+
onBindOAuth={(provider) => console.log(`${provider.provider} bound!`)}
|
|
26
|
+
onUnbindOAuth={(account) => console.log(`${account.provider} unbound!`)}>
|
|
27
|
+
{/* Your application components */}
|
|
28
|
+
</OAuthProvider>
|
|
29
|
+
</SessionProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**OAuthProvider 的 Props**
|
|
35
|
+
|
|
36
|
+
<x-field-group>
|
|
37
|
+
<x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="将有权访问 OAuth 上下文的子组件。"></x-field>
|
|
38
|
+
<x-field data-name="locale" data-type="string" data-default="en" data-desc="用于 UI 消息和提示的语言。"></x-field>
|
|
39
|
+
<x-field data-name="onBindOAuth" data-type="function" data-desc="用户成功绑定 OAuth 帐户后触发的回调函数。"></x-field>
|
|
40
|
+
<x-field data-name="onUnbindOAuth" data-type="function" data-desc="用户成功解绑 OAuth 帐户后触发的回调函数。"></x-field>
|
|
41
|
+
<x-field data-name="onSwitchPassport" data-type="function" data-desc="用户切换通行证后触发的回调函数。"></x-field>
|
|
42
|
+
<x-field data-name="session" data-type="object" data-desc="当前用户会话对象,切换通行证 UI 时需要。"></x-field>
|
|
43
|
+
</x-field-group>
|
|
44
|
+
|
|
45
|
+
### 2. 使用 useOAuth Hook
|
|
46
|
+
|
|
47
|
+
`useOAuth` Hook 提供了与 OAuth 身份验证流程交互的函数。
|
|
48
|
+
|
|
49
|
+
```jsx useOAuth Hook icon=logos:react
|
|
50
|
+
import { useOAuth } from '@arcblock/did-connect-react/lib/OAuth';
|
|
51
|
+
|
|
52
|
+
function SocialLoginButtons() {
|
|
53
|
+
const { loginOAuth, getOAuthConfigList, bindAuthLoading } = useOAuth();
|
|
54
|
+
const [providers, setProviders] = React.useState([]);
|
|
55
|
+
|
|
56
|
+
React.useEffect(() => {
|
|
57
|
+
getOAuthConfigList().then(setProviders);
|
|
58
|
+
}, [getOAuthConfigList]);
|
|
59
|
+
|
|
60
|
+
const handleLogin = async (provider) => {
|
|
61
|
+
try {
|
|
62
|
+
const result = await loginOAuth({ provider: provider.provider });
|
|
63
|
+
console.log('Login successful:', result);
|
|
64
|
+
// Handle login result, e.g., update session
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Login failed:', error.message);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if (providers.length === 0) {
|
|
71
|
+
return <p>No third-party login methods configured.</p>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div>
|
|
76
|
+
{providers.map((p) => (
|
|
77
|
+
<button key={p.provider} onClick={() => handleLogin(p)} disabled={bindAuthLoading}>
|
|
78
|
+
Login with {p.provider}
|
|
79
|
+
</button>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 核心函数
|
|
87
|
+
|
|
88
|
+
- **`loginOAuth({ provider }, { action, ... })`**:为特定提供商启动登录流程。将打开一个弹出窗口供用户进行身份验证。
|
|
89
|
+
- **`bindOAuth({ session, oauthItem })`**:将新的社交帐户绑定到当前登录的用户。
|
|
90
|
+
- **`unbindOAuth({ session, connectedAccount })`**:从当前用户解绑社交帐户。
|
|
91
|
+
- **`getOAuthConfigList()`**:异步获取在 Blocklet 设置中配置的已启用 OAuth 提供商列表。
|
|
92
|
+
- **`switchOAuthPassport(user)`**:打开一个对话框,用于在与同一 OAuth 身份关联的不同用户帐户(通行证)之间切换。
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Passkeys(无密码)
|
|
97
|
+
|
|
98
|
+
使用基于 WebAuthn 标准的 Passkeys 启用现代、安全且无密码的身份验证。这允许用户通过生物识别(指纹、面部 ID)、设备 PIN 或安全密钥登录。
|
|
99
|
+
|
|
100
|
+
### 1. 使用 PasskeyProvider 进行设置
|
|
101
|
+
|
|
102
|
+
使用 `PasskeyProvider` 包裹您的应用程序以启用 Passkey 功能。
|
|
103
|
+
|
|
104
|
+
```jsx PasskeyProvider Setup icon=logos:react
|
|
105
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
106
|
+
import { PasskeyProvider } from '@arcblock/did-connect-react/lib/Passkey';
|
|
107
|
+
|
|
108
|
+
function App() {
|
|
109
|
+
return (
|
|
110
|
+
<SessionProvider>
|
|
111
|
+
<PasskeyProvider
|
|
112
|
+
onAddPasskey={(result) => console.log('Passkey added!', result)}
|
|
113
|
+
onRemovePasskey={(result) => console.log('Passkey removed!', result)}>
|
|
114
|
+
{/* Your application components */}
|
|
115
|
+
</PasskeyProvider>
|
|
116
|
+
</SessionProvider>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**PasskeyProvider 的 Props**
|
|
122
|
+
|
|
123
|
+
<x-field-group>
|
|
124
|
+
<x-field data-name="children" data-type="ReactNode" data-required="true" data-desc="将有权访问 Passkey 上下文的子组件。"></x-field>
|
|
125
|
+
<x-field data-name="locale" data-type="string" data-default="en" data-desc="用于 UI 消息和提示的语言。"></x-field>
|
|
126
|
+
<x-field data-name="onAddPasskey" data-type="function" data-desc="用户成功添加 Passkey 后触发的回调函数。"></x-field>
|
|
127
|
+
<x-field data-name="onRemovePasskey" data-type="function" data-desc="用户成功移除 Passkey 后触发的回调函数。"></x-field>
|
|
128
|
+
<x-field data-name="onSwitchPassport" data-type="function" data-desc="用户切换通行证后触发的回调函数。"></x-field>
|
|
129
|
+
<x-field data-name="session" data-type="object" data-desc="当前用户会话对象,切换通行证 UI 时需要。"></x-field>
|
|
130
|
+
</x-field-group>
|
|
131
|
+
|
|
132
|
+
### 2. 使用 usePasskey Hook
|
|
133
|
+
|
|
134
|
+
`usePasskey` Hook 提供了 Passkey 注册和身份验证所需的所有必要函数。
|
|
135
|
+
|
|
136
|
+
```jsx usePasskey Hook icon=logos:react
|
|
137
|
+
import { usePasskey } from '@arcblock/did-connect-react/lib/Passkey';
|
|
138
|
+
import { useSession } from '@arcblock/did-connect-react';
|
|
139
|
+
|
|
140
|
+
function PasskeyAuth() {
|
|
141
|
+
const { loginPasskey, connectPasskey, connecting } = usePasskey();
|
|
142
|
+
const { session } = useSession();
|
|
143
|
+
|
|
144
|
+
const handleLogin = async () => {
|
|
145
|
+
try {
|
|
146
|
+
const result = await loginPasskey();
|
|
147
|
+
console.log('Passkey login successful:', result);
|
|
148
|
+
// Handle login result
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error('Passkey login failed:', error.message);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleConnect = async () => {
|
|
155
|
+
// This should be called when a user is already logged in
|
|
156
|
+
// and wants to add a passkey in their profile settings.
|
|
157
|
+
if (!session.user) {
|
|
158
|
+
alert('You must be logged in to add a passkey.');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
await connectPasskey();
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error('Failed to connect passkey:', error.message);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div>
|
|
170
|
+
<button onClick={handleLogin}>Login with Passkey</button>
|
|
171
|
+
{session.user && (
|
|
172
|
+
<button onClick={handleConnect} disabled={connecting}>
|
|
173
|
+
{connecting ? 'Connecting...' : 'Add a Passkey'}
|
|
174
|
+
</button>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 核心函数
|
|
182
|
+
- **`loginPasskey({ action, ... })`**:启动 Passkey 身份验证流程(也称为断言)。这用于登录现有用户。
|
|
183
|
+
- **`connectPasskey(extraParams)`**:一个高级函数,用于创建新的 Passkey 并将其绑定到当前用户的帐户。它处理完整的注册过程。
|
|
184
|
+
- **`disconnectPasskey({ session, connectedAccount })`**:成功验证后,从当前用户的帐户中移除一个 Passkey。
|
|
185
|
+
- **`createPasskey(params)`**:启动 WebAuthn 注册过程的底层函数。`connectPasskey` 内部使用此函数。
|
|
186
|
+
- **`verifyPasskey(params)`**:启动 WebAuthn 身份验证过程的底层函数。`loginPasskey` 和 `disconnectPasskey` 内部使用此函数。
|
|
187
|
+
- **`switchPassport(user)`**:打开一个对话框,用于在可能共享 Passkeys 的不同用户帐户(通行证)之间切换。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 统一登录
|
|
192
|
+
|
|
193
|
+
统一登录允许一组关联的 Blocklet 应用程序(一个“统一登录站点群”)共享同一个登录会话。当用户登录到指定的“主”站点时,他们可以在任何“成员”站点上被自动验证,而无需再次登录。
|
|
194
|
+
|
|
195
|
+
### 1. 概念与设置
|
|
196
|
+
|
|
197
|
+
此功能依赖于您 Blocklet 设置中的主-成员站点配置。`FederatedProvider` 组件是处理此功能在现代浏览器中正常工作所需的跨域通信所必需的,特别是在管理第三方 Cookie 访问方面。
|
|
198
|
+
|
|
199
|
+
与其他 Provider 一样,`FederatedProvider` 应包含在您的组件树中,通常位于 `SessionProvider` 内部。
|
|
200
|
+
|
|
201
|
+
```jsx FederatedProvider Setup icon=logos:react
|
|
202
|
+
import { SessionProvider } from '@arcblock/did-connect-react';
|
|
203
|
+
import { FederatedProvider } from '@arcblock/did-connect-react/lib/Federated';
|
|
204
|
+
|
|
205
|
+
function App() {
|
|
206
|
+
return (
|
|
207
|
+
<SessionProvider>
|
|
208
|
+
<FederatedProvider>
|
|
209
|
+
{/* Your application components */}
|
|
210
|
+
</FederatedProvider>
|
|
211
|
+
</SessionProvider>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 2. 使用方法
|
|
217
|
+
|
|
218
|
+
统一登录逻辑直接集成在会话管理中。您可以使用 `useSession` 返回的 `session` 对象上的 `loginFederated` 函数来触发它。
|
|
219
|
+
|
|
220
|
+
`loginFederated` 支持两种模式:
|
|
221
|
+
- **`auto`**:如果用户在主站点上拥有活动会话,则尝试静默登录用户。这非常适合在页面加载时进行检查。
|
|
222
|
+
- **`manual`**:启动标准的 DID Connect 登录流程。成功登录后,它还会与主站点建立统一登录会话。
|
|
223
|
+
|
|
224
|
+
```jsx Federated Login Example icon=logos:react
|
|
225
|
+
import { useSession } from '@arcblock/did-connect-react';
|
|
226
|
+
import React from 'react';
|
|
227
|
+
|
|
228
|
+
function FederatedLogin() {
|
|
229
|
+
const { session } = useSession();
|
|
230
|
+
const { federatedEnabled, loginFederated } = session;
|
|
231
|
+
|
|
232
|
+
// Attempt auto-login on component mount
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
if (federatedEnabled) {
|
|
235
|
+
loginFederated((err) => {
|
|
236
|
+
if (err) {
|
|
237
|
+
console.warn('Auto federated login failed:', err);
|
|
238
|
+
} else {
|
|
239
|
+
console.log('Auto federated login successful!');
|
|
240
|
+
}
|
|
241
|
+
}, { mode: 'auto' });
|
|
242
|
+
}
|
|
243
|
+
}, [federatedEnabled, loginFederated]);
|
|
244
|
+
|
|
245
|
+
const handleManualLogin = () => {
|
|
246
|
+
loginFederated((err) => {
|
|
247
|
+
if (err) console.error('Manual federated login failed:', err);
|
|
248
|
+
}, { mode: 'manual' });
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
if (!federatedEnabled) {
|
|
252
|
+
return <p>Federated login is not enabled.</p>;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<button onClick={handleManualLogin}>
|
|
257
|
+
Login with Master Site Account
|
|
258
|
+
</button>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# ユーティリティ
|
|
2
|
+
|
|
3
|
+
`@arcblock/did-connect-react`ライブラリは、認証フロー、データ処理、API通信に関連する一般的なタスクを簡素化するために設計されたユーティリティ関数のコレクションをエクスポートします。コアコンポーネントとフックがほとんどのユースケースを処理しますが、これらのユーティリティは高度な統合やカスタム実装のための詳細な制御を提供します。
|
|
4
|
+
|
|
5
|
+
## APIクライアント
|
|
6
|
+
|
|
7
|
+
### createAxios
|
|
8
|
+
|
|
9
|
+
この関数は、事前設定された`axios`インスタンスを作成するためのファクトリです。`x-did-connect-version`や`x-blocklet-visitor-id`などの必須ヘッダーを自動的に含み、Blockletベースのサービスとの適切な通信を保証します。アプリケーションでAPIクライアントを作成する推奨される方法です。
|
|
10
|
+
|
|
11
|
+
**パラメータ**
|
|
12
|
+
|
|
13
|
+
<x-field-group>
|
|
14
|
+
<x-field data-name="options" data-type="object" data-required="false" data-desc="標準的なAxios設定オブジェクト。"></x-field>
|
|
15
|
+
<x-field data-name="lazyOptions" data-type="object" data-required="false" data-desc="遅延送信のための設定。">
|
|
16
|
+
<x-field data-name="lazy" data-type="boolean" data-default="false" data-desc="遅延送信を有効にするかどうか。"></x-field>
|
|
17
|
+
<x-field data-name="lazyTime" data-type="number" data-default="300" data-desc="遅延送信のデバウンス時間(ミリ秒)。"></x-field>
|
|
18
|
+
</x-field>
|
|
19
|
+
</x-field-group>
|
|
20
|
+
|
|
21
|
+
**戻り値**
|
|
22
|
+
|
|
23
|
+
<x-field data-name="axiosInstance" data-type="AxiosInstance" data-desc="設定済みのAxiosインスタンス。"></x-field>
|
|
24
|
+
|
|
25
|
+
**例**
|
|
26
|
+
|
|
27
|
+
```javascript apiClient.js icon=logos:javascript
|
|
28
|
+
import { createAxios } from '@arcblock/did-connect-react/lib/utils';
|
|
29
|
+
|
|
30
|
+
const apiClient = createAxios({
|
|
31
|
+
baseURL: '/api',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export default apiClient;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## URLとポップアップの処理
|
|
38
|
+
|
|
39
|
+
これらの関数は、DID Connect認証プロセス中に使用されるURLとポップアップウィンドウの管理を支援します。
|
|
40
|
+
|
|
41
|
+
| 関数 | 説明 |
|
|
42
|
+
| :--- | :--- |
|
|
43
|
+
| `encodeConnectUrl(url)` | URLを`__connect_url__`クエリパラメータとして安全に渡せるようにエンコードします。 |
|
|
44
|
+
| `decodeConnectUrl(encoded)` | `encodeConnectUrl`でエンコードされたURLをデコードします。 |
|
|
45
|
+
| `parseTokenFromConnectUrl(connectUrl)` | DID Connect URLからセッショントークン(`_t_`)を抽出します。 |
|
|
46
|
+
| `openPopup(url, options)` | 中央に配置された新しいポップアップウィンドウを開きます。`DidConnect`コンポーネントが内部で使用し、ウォレット接続インターフェースを表示します。ポップアップがブロックされた場合は`NotOpenError`をスローします。 |
|
|
47
|
+
| `runPopup(config)` | `openPopup`で作成されたポップアップのライフサイクルを管理するプロミスベースのラッパーです。ポップアップからの`message`イベントをリッスンし、タイムアウトを処理し、認証フローが完了したときに解決します。 |
|
|
48
|
+
| `decodeUrlParams()` | 現在のウィンドウのURLからカスタムの`__did-connect__`パラメータを解析します。 |
|
|
49
|
+
|
|
50
|
+
**例:カスタムポップアップフロー**
|
|
51
|
+
|
|
52
|
+
```javascript customAuthButton.js icon=logos:javascript
|
|
53
|
+
import { openPopup, runPopup } from '@arcblock/did-connect-react/lib/utils';
|
|
54
|
+
|
|
55
|
+
const handleCustomLogin = async () => {
|
|
56
|
+
const authUrl = 'https://your-auth-service.com/connect';
|
|
57
|
+
try {
|
|
58
|
+
const popup = openPopup(authUrl);
|
|
59
|
+
const result = await runPopup({ popup, timeoutInSeconds: 600 });
|
|
60
|
+
console.log('Authentication successful:', result);
|
|
61
|
+
// ログイン成功時の処理
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('Authentication failed:', error.message);
|
|
64
|
+
// ポップアップが閉じられた、またはタイムアウトした場合の処理
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## セッションとCookieの管理
|
|
70
|
+
|
|
71
|
+
これらのヘルパーは、ユーザーの接続情報をCookieに読み書きするために使用され、ページ読み込みをまたいだセッションの永続化を可能にします。
|
|
72
|
+
|
|
73
|
+
| 関数 | 説明 |
|
|
74
|
+
| :--- | :--- |
|
|
75
|
+
| `getConnectedInfo(data)` | 接続リクエストからの生のレスポンスデータを、Cookieストレージに適した標準化されたオブジェクトにフォーマットします。 |
|
|
76
|
+
| `updateConnectedInfo(info, parsed)` | 接続が成功した後、必要なCookie(`connected_did`、`connected_pk`、`connected_app`)を設定します。これにより、ライブラリは後続の認証チェックを最適化できます。 |
|
|
77
|
+
| `getVisitorId()` | Cookieからユニークな訪問者IDを取得します。 |
|
|
78
|
+
| `setVisitorId(id)` | Cookieにユニークな訪問者IDを設定します。 |
|
|
79
|
+
|
|
80
|
+
**例**
|
|
81
|
+
|
|
82
|
+
```javascript sessionManager.js icon=logos:javascript
|
|
83
|
+
import { getConnectedInfo, updateConnectedInfo } from '@arcblock/did-connect-react/lib/utils';
|
|
84
|
+
|
|
85
|
+
// 'authResponse'がログインAPIから返されたオブジェクトであると仮定します
|
|
86
|
+
function persistSession(authResponse) {
|
|
87
|
+
const connectedInfo = getConnectedInfo(authResponse);
|
|
88
|
+
updateConnectedInfo(connectedInfo, true);
|
|
89
|
+
console.log('セッション情報がCookieに保存されました。');
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 暗号化ユーティリティ
|
|
94
|
+
|
|
95
|
+
クライアントサイドでの暗号化または復号化が必要な高度なシナリオのために、ライブラリは`tweetnacl-sealedbox-js`ライブラリをラップするヘルパーを公開しています。
|
|
96
|
+
|
|
97
|
+
| 関数 | 説明 |
|
|
98
|
+
| :--- | :--- |
|
|
99
|
+
| `encodeKey(key)` | キーを伝送用にBase64URLエンコードします。 |
|
|
100
|
+
| `decodeKey(str)` | Base64URL文字列を`Uint8Array`キーにデコードします。 |
|
|
101
|
+
| `encrypt(value, encryptKey)` | 公開鍵を使用して文字列値を暗号化します。 |
|
|
102
|
+
| `decrypt(value, encryptKey, decryptKey)` | 対応する公開鍵と秘密鍵を使用してbase64文字列を復号化します。 |
|
|
103
|
+
|
|
104
|
+
## エラーハンドリング
|
|
105
|
+
|
|
106
|
+
ユーザーにより良いフィードバックを提供するために、これらの関数を使用して技術的なエラーオブジェクトを人間が読めるメッセージに解析できます。
|
|
107
|
+
|
|
108
|
+
| 関数 | 説明 |
|
|
109
|
+
| :--- | :--- |
|
|
110
|
+
| `getApiErrorMessage(err, defaultMessage)` | `axios`エラーオブジェクトからユーザーフレンドリーなエラーメッセージを抽出します。 |
|
|
111
|
+
| `getWebAuthnErrorMessage(err, defaultMessage, t)` | WebAuthn/Passkey固有のエラー(例:ユーザーによるキャンセル、ブラウザ非対応)を処理し、ローカライズされたユーザーフレンドリーなメッセージを返します。 |
|
|
112
|
+
|
|
113
|
+
**例**
|
|
114
|
+
|
|
115
|
+
```javascript errorHandling.js icon=logos:javascript
|
|
116
|
+
import { getApiErrorMessage } from '@arcblock/did-connect-react/lib/utils';
|
|
117
|
+
import apiClient from './apiClient';
|
|
118
|
+
|
|
119
|
+
async function fetchData() {
|
|
120
|
+
try {
|
|
121
|
+
const response = await apiClient.get('/data');
|
|
122
|
+
return response.data;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const message = getApiErrorMessage(error, 'データの取得に失敗しました。');
|
|
125
|
+
alert(message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
これらのユーティリティを活用することで、より複雑でカスタマイズされた認証体験を構築できます。エクスポートされたすべてのメンバーとその型の完全なリストについては、[APIリファレンス](./api-reference.md)を参照してください。
|