react-unified-auth 1.0.1
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/README.md +252 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.esm.js +4248 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +4262 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# React Unified Auth
|
|
2
|
+
|
|
3
|
+
一个用于三方登录的统一入口React组件库,支持动态表单和可配置的认证流程。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 动态表单渲染:通过HTTP请求获取表单结构并动态渲染
|
|
8
|
+
- 可配置的认证流程:支持自定义API端点和参数
|
|
9
|
+
- 预构建的UI组件:登录表单、用户信息框、社交登录按钮等
|
|
10
|
+
- TypeScript支持:完整的类型定义
|
|
11
|
+
- React Hooks:提供便捷的认证和表单管理hooks
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install react-unified-auth
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 使用方法
|
|
20
|
+
|
|
21
|
+
### 1. 配置AuthProvider
|
|
22
|
+
|
|
23
|
+
在你的应用根组件中包裹`AuthProvider`:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { AuthProvider } from 'react-social-auth';
|
|
27
|
+
|
|
28
|
+
function App() {
|
|
29
|
+
const config = {
|
|
30
|
+
apiUrl: 'https://your-api.com',
|
|
31
|
+
clientId: 'your-client-id',
|
|
32
|
+
clientSecret: 'your-client-secret',
|
|
33
|
+
redirectUri: 'https://your-app.com/callback',
|
|
34
|
+
headers: {
|
|
35
|
+
'X-Custom-Header': 'value',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<AuthProvider config={config}>
|
|
41
|
+
<YourApp />
|
|
42
|
+
</AuthProvider>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. 使用登录表单
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { LoginForm } from 'react-social-auth';
|
|
51
|
+
|
|
52
|
+
function LoginPage() {
|
|
53
|
+
return (
|
|
54
|
+
<div>
|
|
55
|
+
<LoginForm
|
|
56
|
+
formId="login-form"
|
|
57
|
+
onSuccess={(data) => console.log('Login success:', data)}
|
|
58
|
+
onError={(error) => console.error('Login error:', error)}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. 使用用户信息框
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { UserInfoBox, useAuth } from 'react-social-auth';
|
|
69
|
+
|
|
70
|
+
function UserProfile() {
|
|
71
|
+
const { user, logout } = useAuth();
|
|
72
|
+
|
|
73
|
+
if (!user) return null;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<UserInfoBox
|
|
77
|
+
user={user}
|
|
78
|
+
onLogout={logout}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. 使用社交登录
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { SocialLogin } from 'react-social-auth';
|
|
88
|
+
|
|
89
|
+
function SocialLoginPage() {
|
|
90
|
+
const providers = [
|
|
91
|
+
{
|
|
92
|
+
id: 'google',
|
|
93
|
+
name: 'Google',
|
|
94
|
+
icon: '/google-icon.png',
|
|
95
|
+
authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
96
|
+
scope: ['openid', 'email', 'profile'],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'github',
|
|
100
|
+
name: 'GitHub',
|
|
101
|
+
icon: '/github-icon.png',
|
|
102
|
+
authUrl: 'https://github.com/login/oauth/authorize',
|
|
103
|
+
scope: ['user:email'],
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const handleSocialLogin = (provider) => {
|
|
108
|
+
window.location.href = provider.authUrl;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<SocialLogin
|
|
113
|
+
providers={providers}
|
|
114
|
+
onLogin={handleSocialLogin}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 5. 使用动态表单
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { DynamicForm } from 'react-social-auth';
|
|
124
|
+
|
|
125
|
+
function CustomForm() {
|
|
126
|
+
const fields = [
|
|
127
|
+
{
|
|
128
|
+
name: 'username',
|
|
129
|
+
type: 'text',
|
|
130
|
+
label: 'Username',
|
|
131
|
+
required: true,
|
|
132
|
+
validation: {
|
|
133
|
+
minLength: 3,
|
|
134
|
+
maxLength: 20,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'email',
|
|
139
|
+
type: 'email',
|
|
140
|
+
label: 'Email',
|
|
141
|
+
required: true,
|
|
142
|
+
validation: {
|
|
143
|
+
pattern: '^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
const handleSubmit = (values) => {
|
|
149
|
+
console.log('Form submitted:', values);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<DynamicForm
|
|
154
|
+
fields={fields}
|
|
155
|
+
onSubmit={handleSubmit}
|
|
156
|
+
submitText="Register"
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## API配置
|
|
163
|
+
|
|
164
|
+
### AuthConfig
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
interface AuthConfig {
|
|
168
|
+
apiUrl: string; // API基础URL
|
|
169
|
+
clientId?: string; // 客户端ID
|
|
170
|
+
clientSecret?: string; // 客户端密钥
|
|
171
|
+
redirectUri?: string; // 重定向URI
|
|
172
|
+
scope?: string[]; // 授权范围
|
|
173
|
+
headers?: Record<string, string>; // 自定义请求头
|
|
174
|
+
timeout?: number; // 请求超时时间(毫秒)
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 表单字段类型
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
type FormFieldType = 'text' | 'email' | 'password' | 'number' | 'select' | 'checkbox' | 'radio' | 'textarea';
|
|
182
|
+
|
|
183
|
+
interface FormField {
|
|
184
|
+
name: string;
|
|
185
|
+
type: FormFieldType;
|
|
186
|
+
label: string;
|
|
187
|
+
placeholder?: string;
|
|
188
|
+
required?: boolean;
|
|
189
|
+
options?: Array<{ label: string; value: string }>;
|
|
190
|
+
validation?: {
|
|
191
|
+
pattern?: string;
|
|
192
|
+
minLength?: number;
|
|
193
|
+
maxLength?: number;
|
|
194
|
+
min?: number;
|
|
195
|
+
max?: number;
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Hooks
|
|
201
|
+
|
|
202
|
+
### useAuth
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const { user, loading, error, login, logout, getUserInfo, isAuthenticated } = useAuth();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### useDynamicForm
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const { formConfig, loading, error } = useDynamicForm(formId);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## API端点
|
|
215
|
+
|
|
216
|
+
组件库会调用以下API端点:
|
|
217
|
+
|
|
218
|
+
- `GET /forms/:formId` - 获取动态表单配置
|
|
219
|
+
- `POST /auth/login` - 用户登录
|
|
220
|
+
- `POST /auth/logout` - 用户登出
|
|
221
|
+
- `GET /auth/me` - 获取当前用户信息
|
|
222
|
+
|
|
223
|
+
## 样式自定义
|
|
224
|
+
|
|
225
|
+
组件使用了Tailwind CSS的类名,你可以通过以下方式自定义样式:
|
|
226
|
+
|
|
227
|
+
1. 在你的项目中配置Tailwind CSS
|
|
228
|
+
2. 通过`className` prop传递自定义类名
|
|
229
|
+
3. 覆盖默认样式
|
|
230
|
+
|
|
231
|
+
## 开发
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# 安装依赖
|
|
235
|
+
npm install
|
|
236
|
+
|
|
237
|
+
# 开发模式
|
|
238
|
+
npm run dev
|
|
239
|
+
|
|
240
|
+
# 构建
|
|
241
|
+
npm run build
|
|
242
|
+
|
|
243
|
+
# 类型检查
|
|
244
|
+
npm run typecheck
|
|
245
|
+
|
|
246
|
+
# 代码检查
|
|
247
|
+
npm run lint
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React, { ReactNode } from 'react';
|
|
3
|
+
import { AxiosRequestConfig } from 'axios';
|
|
4
|
+
|
|
5
|
+
interface AuthConfig {
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
clientId?: string;
|
|
8
|
+
clientSecret?: string;
|
|
9
|
+
redirectUri?: string;
|
|
10
|
+
scope?: string[];
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
interface FormField {
|
|
15
|
+
name: string;
|
|
16
|
+
type: 'text' | 'email' | 'password' | 'number' | 'select' | 'checkbox' | 'radio' | 'textarea';
|
|
17
|
+
label: string;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
options?: Array<{
|
|
21
|
+
label: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}>;
|
|
24
|
+
validation?: {
|
|
25
|
+
pattern?: string;
|
|
26
|
+
minLength?: number;
|
|
27
|
+
maxLength?: number;
|
|
28
|
+
min?: number;
|
|
29
|
+
max?: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
interface DynamicFormConfig {
|
|
33
|
+
fields: FormField[];
|
|
34
|
+
submitUrl: string;
|
|
35
|
+
method?: 'POST' | 'PUT' | 'PATCH';
|
|
36
|
+
submitButton?: {
|
|
37
|
+
text: string;
|
|
38
|
+
variant?: 'primary' | 'secondary' | 'outline';
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
interface UserInfo {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
email?: string;
|
|
45
|
+
avatar?: string;
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
}
|
|
48
|
+
interface AuthResponse {
|
|
49
|
+
success: boolean;
|
|
50
|
+
data?: {
|
|
51
|
+
user?: UserInfo;
|
|
52
|
+
token?: string;
|
|
53
|
+
refreshToken?: string;
|
|
54
|
+
};
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
interface SocialProvider {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
icon?: string;
|
|
61
|
+
authUrl: string;
|
|
62
|
+
scope?: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface AuthProviderProps {
|
|
66
|
+
config: AuthConfig;
|
|
67
|
+
children: ReactNode;
|
|
68
|
+
}
|
|
69
|
+
declare function AuthProvider({ config, children }: AuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
70
|
+
declare function useAuthConfig(): AuthConfig;
|
|
71
|
+
|
|
72
|
+
declare function useAuth(): {
|
|
73
|
+
user: UserInfo | null;
|
|
74
|
+
loading: boolean;
|
|
75
|
+
error: string | null;
|
|
76
|
+
login: (credentials: Record<string, any>) => Promise<AuthResponse>;
|
|
77
|
+
logout: () => Promise<void>;
|
|
78
|
+
getUserInfo: () => Promise<UserInfo | null>;
|
|
79
|
+
isAuthenticated: boolean;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
declare function useDynamicForm(formId: string): {
|
|
83
|
+
formConfig: DynamicFormConfig | null;
|
|
84
|
+
loading: boolean;
|
|
85
|
+
error: string | null;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
89
|
+
variant?: 'primary' | 'secondary' | 'outline';
|
|
90
|
+
size?: 'sm' | 'md' | 'lg';
|
|
91
|
+
loading?: boolean;
|
|
92
|
+
fullWidth?: boolean;
|
|
93
|
+
}
|
|
94
|
+
declare function Button({ variant, size, loading, fullWidth, children, disabled, className, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
|
|
96
|
+
interface DynamicFormProps {
|
|
97
|
+
fields: FormField[];
|
|
98
|
+
onSubmit: (values: Record<string, any>) => void;
|
|
99
|
+
submitText?: string;
|
|
100
|
+
submitVariant?: 'primary' | 'secondary' | 'outline';
|
|
101
|
+
loading?: boolean;
|
|
102
|
+
}
|
|
103
|
+
declare function DynamicForm({ fields, onSubmit, submitText, submitVariant, loading, }: DynamicFormProps): react_jsx_runtime.JSX.Element;
|
|
104
|
+
|
|
105
|
+
interface LoginFormProps {
|
|
106
|
+
formId: string;
|
|
107
|
+
onSuccess?: (data: any) => void;
|
|
108
|
+
onError?: (error: string) => void;
|
|
109
|
+
}
|
|
110
|
+
declare function LoginForm({ formId, onSuccess, onError }: LoginFormProps): react_jsx_runtime.JSX.Element | null;
|
|
111
|
+
|
|
112
|
+
interface UserInfoBoxProps {
|
|
113
|
+
user: UserInfo;
|
|
114
|
+
onLogout?: () => void;
|
|
115
|
+
loading?: boolean;
|
|
116
|
+
className?: string;
|
|
117
|
+
}
|
|
118
|
+
declare function UserInfoBox({ user, onLogout, loading, className }: UserInfoBoxProps): react_jsx_runtime.JSX.Element;
|
|
119
|
+
|
|
120
|
+
interface SocialLoginButtonProps {
|
|
121
|
+
provider: SocialProvider;
|
|
122
|
+
onClick: (provider: SocialProvider) => void;
|
|
123
|
+
loading?: boolean;
|
|
124
|
+
className?: string;
|
|
125
|
+
}
|
|
126
|
+
declare function SocialLoginButton({ provider, onClick, loading, className }: SocialLoginButtonProps): react_jsx_runtime.JSX.Element;
|
|
127
|
+
interface SocialLoginProps {
|
|
128
|
+
providers: SocialProvider[];
|
|
129
|
+
onLogin: (provider: SocialProvider) => void;
|
|
130
|
+
loading?: boolean;
|
|
131
|
+
className?: string;
|
|
132
|
+
}
|
|
133
|
+
declare function SocialLogin({ providers, onLogin, loading, className }: SocialLoginProps): react_jsx_runtime.JSX.Element | null;
|
|
134
|
+
|
|
135
|
+
declare class ApiClient {
|
|
136
|
+
private client;
|
|
137
|
+
constructor(config: {
|
|
138
|
+
baseURL: string;
|
|
139
|
+
timeout?: number;
|
|
140
|
+
headers?: Record<string, string>;
|
|
141
|
+
});
|
|
142
|
+
get<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
143
|
+
post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
144
|
+
put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
145
|
+
patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
|
|
146
|
+
delete<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare function validateField(field: FormField, value: any): {
|
|
150
|
+
valid: boolean;
|
|
151
|
+
error?: string;
|
|
152
|
+
};
|
|
153
|
+
declare function validateForm(fields: FormField[], values: Record<string, any>): {
|
|
154
|
+
valid: boolean;
|
|
155
|
+
errors: Record<string, string>;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export { ApiClient, AuthConfig, AuthProvider, AuthProviderProps, AuthResponse, Button, ButtonProps, DynamicForm, DynamicFormConfig, DynamicFormProps, FormField, LoginForm, LoginFormProps, SocialLogin, SocialLoginButton, SocialLoginButtonProps, SocialLoginProps, SocialProvider, UserInfo, UserInfoBox, UserInfoBoxProps, useAuth, useAuthConfig, useDynamicForm, validateField, validateForm };
|