认证
ONE SDK 支持两种认证流程:
| 流程 | 适用场景 | 所需 Provider |
|---|---|---|
| 邮件 OTP | 移动应用、非加密货币用户 | OneProvider |
| 钱包签名 | 已连接钱包的 Web3 原生用户 | OneProvider + OneThirdwebProvider |
两种流程都会生成一个会话令牌,存储在 SDK 上下文中。后续所有 API 调用将自动携带认证信息。
邮件 OTP 流程
1. 发送 OTP
SendOtp.tsx
import { useOneAuth } from "@one_deploy/sdk/hooks";
export function SendOtp() {
const { sendEmailOtp, isLoading, error } = useOneAuth();
const [email, setEmail] = React.useState("");
const handleSend = async () => {
const result = await sendEmailOtp({ email });
if (result.success) {
// Navigate to the verification screen
console.log("OTP sent to", email);
}
};
return (
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
<button onClick={handleSend} disabled={isLoading}>
{isLoading ? "Sending..." : "Send Code"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}
2. 验证 OTP
VerifyOtp.tsx
import { useOneAuth } from "@one_deploy/sdk/hooks";
export function VerifyOtp({ email }: { email: string }) {
const { verifyEmailOtp, isLoading, error } = useOneAuth();
const [code, setCode] = React.useState("");
const handleVerify = async () => {
const result = await verifyEmailOtp({ email, code });
if (result.success) {
console.log("Authenticated as:", result.user.email);
console.log("Access token:", result.accessToken);
// The SDK context is now authenticated.
// All hook calls and engine requests carry the token automatically.
}
};
return (
<div>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="6-digit code"
maxLength={6}
/>
<button onClick={handleVerify} disabled={isLoading}>
{isLoading ? "Verifying..." : "Verify"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}
完整邮件 OTP 示例
EmailLogin.tsx
import React, { useState } from "react";
import { useOneAuth } from "@one_deploy/sdk/hooks";
type Step = "email" | "otp" | "done";
export function EmailLogin() {
const { sendEmailOtp, verifyEmailOtp, isLoading, error } = useOneAuth();
const [step, setStep] = useState<Step>("email");
const [email, setEmail] = useState("");
const [code, setCode] = useState("");
const handleSendOtp = async () => {
const result = await sendEmailOtp({ email });
if (result.success) setStep("otp");
};
const handleVerifyOtp = async () => {
const result = await verifyEmailOtp({ email, code });
if (result.success) setStep("done");
};
if (step === "done") {
return <p>Signed in as {email}</p>;
}
return (
<div>
{step === "email" && (
<>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
<button onClick={handleSendOtp} disabled={isLoading}>
Send OTP
</button>
</>
)}
{step === "otp" && (
<>
<p>Enter the code sent to {email}</p>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="6-digit code"
maxLength={6}
/>
<button onClick={handleVerifyOtp} disabled={isLoading}>
Verify
</button>
</>
)}
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}
钱包签名流程
如果用户已通过 OneThirdwebProvider 连接了钱包,你可以通过请求消息签名来认证用户,无需邮箱。
WalletLogin.tsx
import { useOneAuth, useOneWallet } from "@one_deploy/sdk/hooks";
export function WalletLogin() {
const { authWithWallet, isLoading, error } = useOneAuth();
const { address, isConnected } = useOneWallet();
const handleAuth = async () => {
if (!address) return;
const result = await authWithWallet({
address,
// The SDK generates a SIWE (Sign-In with Ethereum) message and
// prompts the connected wallet to sign it.
});
if (result.success) {
console.log("Authenticated wallet:", result.user.walletAddress);
console.log("Access token:", result.accessToken);
}
};
if (!isConnected) {
return <p>Connect your wallet first.</p>;
}
return (
<div>
<p>Connected: {address}</p>
<button onClick={handleAuth} disabled={isLoading}>
{isLoading ? "Signing..." : "Sign In with Wallet"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}
令牌管理
认证完成后,SDK 会将访问令牌和刷新令牌存储在内存中(Web)或配置的 StorageAdapter 中(React Native)。SDK 会在令牌过期前自动刷新,但你也可以手动管理。
刷新令牌
import { useOneAuth } from "@one_deploy/sdk/hooks";
function TokenManager() {
const { refreshToken } = useOneAuth();
const handleRefresh = async () => {
const result = await refreshToken();
if (result.success) {
console.log("New access token:", result.accessToken);
console.log("Expires at:", new Date(result.expiresAt).toISOString());
}
};
return <button onClick={handleRefresh}>Refresh Token</button>;
}
获取当前用户
import { useOneAuth } from "@one_deploy/sdk/hooks";
function UserProfile() {
const { getCurrentUser } = useOneAuth();
const [user, setUser] = React.useState<OneUser | null>(null);
React.useEffect(() => {
getCurrentUser().then(setUser);
}, [getCurrentUser]);
if (!user) return <p>Not signed in.</p>;
return (
<div>
<p>Email: {user.email ?? "N/A"}</p>
<p>Wallet: {user.walletAddress ?? "N/A"}</p>
<p>User ID: {user.id}</p>
<p>Created: {new Date(user.createdAt).toLocaleDateString()}</p>
</div>
);
}
登出
import { useOneAuth } from "@one_deploy/sdk/hooks";
function SignOutButton() {
const { signOut } = useOneAuth();
const handleSignOut = async () => {
await signOut();
// Auth state is cleared. Hooks that depend on auth will reset.
console.log("Signed out");
};
return <button onClick={handleSignOut}>Sign Out</button>;
}
会话管理
SDK 支持多个并发会话(例如用户同时在手机和笔记本电脑上登录)。你可以列出和撤销会话。
列出活跃会话
import { useOneAuth } from "@one_deploy/sdk/hooks";
function ActiveSessions() {
const { getActiveSessions } = useOneAuth();
const [sessions, setSessions] = React.useState<OneSession[]>([]);
React.useEffect(() => {
getActiveSessions().then(setSessions);
}, [getActiveSessions]);
return (
<ul>
{sessions.map((session) => (
<li key={session.id}>
{session.deviceName ?? "Unknown device"} --{" "}
{session.isCurrent ? "This device" : session.lastActiveAt}
</li>
))}
</ul>
);
}
撤销会话
import { useOneAuth } from "@one_deploy/sdk/hooks";
function RevokeSession({ sessionId }: { sessionId: string }) {
const { revokeSession } = useOneAuth();
const handleRevoke = async () => {
const result = await revokeSession({ sessionId });
if (result.success) {
console.log("Session revoked:", sessionId);
}
};
return <button onClick={handleRevoke}>Revoke</button>;
}
直接使用 Engine 客户端
所有认证方法也可以通过 OneEngineClient 在服务端或无界面场景中使用:
server/auth.ts
import { OneEngineClient } from "@one_deploy/sdk/services";
const engine = new OneEngineClient({
baseUrl: process.env.ONE_ENGINE_URL!,
clientId: process.env.ONE_CLIENT_ID!,
secretKey: process.env.ONE_SECRET_KEY!, // server only
});
// Send OTP
await engine.sendEmailOtp({ email: "user@example.com" });
// Verify OTP
const authResult = await engine.verifyEmailOtp({
email: "user@example.com",
code: "123456",
});
// Use the token for subsequent calls
engine.setAccessToken(authResult.accessToken);
// Get user
const user = await engine.getCurrentUser();
// List sessions
const sessions = await engine.getActiveSessions();
// Revoke a session
await engine.revokeSession({ sessionId: "sess_abc123" });
// Sign out (invalidates current token)
await engine.signOut();
类型参考
import type { OneUser, OneSession, AuthResult } from "@one_deploy/sdk/types";
interface OneUser {
id: string;
email?: string;
walletAddress?: string;
createdAt: string;
updatedAt: string;
}
interface OneSession {
id: string;
userId: string;
deviceName?: string;
ipAddress?: string;
lastActiveAt: string;
createdAt: string;
isCurrent: boolean;
}
interface AuthResult {
success: boolean;
user: OneUser;
accessToken: string;
refreshToken: string;
expiresAt: number; // Unix ms
}