@ahoo-wang/fetcher-cosec 3.0.2 → 3.0.5
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 +104 -0
- package/README.zh-CN.md +104 -0
- package/dist/cosecConfigurer.d.ts +88 -0
- package/dist/cosecConfigurer.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +285 -231
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/resourceAttributionRequestInterceptor.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ This package provides seamless integration between the Fetcher HTTP client and t
|
|
|
26
26
|
- **⚡ Performance Optimized**: Minimal overhead with connection pooling and caching
|
|
27
27
|
- **🛠️ TypeScript First**: Complete type definitions with strict type safety
|
|
28
28
|
- **🔌 Pluggable Architecture**: Modular design for easy integration and customization
|
|
29
|
+
- **⚙️ Simplified Configuration**: One-line setup with `CoSecConfigurer` for minimal configuration overhead
|
|
29
30
|
|
|
30
31
|
## 🚀 Quick Start
|
|
31
32
|
|
|
@@ -112,6 +113,70 @@ fetcher.interceptors.response.use(
|
|
|
112
113
|
);
|
|
113
114
|
```
|
|
114
115
|
|
|
116
|
+
## 🚀 Simplified Setup (Recommended)
|
|
117
|
+
|
|
118
|
+
For a much simpler setup experience, use the `CoSecConfigurer` class which automatically handles all the complex dependency creation and interceptor configuration:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
122
|
+
import { CoSecConfigurer } from '@ahoo-wang/fetcher-cosec';
|
|
123
|
+
|
|
124
|
+
// Create a Fetcher instance
|
|
125
|
+
const fetcher = new Fetcher({
|
|
126
|
+
baseURL: 'https://api.example.com',
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Create CoSec configurer with minimal required configuration
|
|
130
|
+
const configurer = new CoSecConfigurer({
|
|
131
|
+
appId: 'your-app-id',
|
|
132
|
+
tokenRefresher: {
|
|
133
|
+
refresh: async token => {
|
|
134
|
+
// Implement your token refresh logic
|
|
135
|
+
const response = await fetch('/api/auth/refresh', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify({ refreshToken: token.refreshToken }),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
throw new Error('Token refresh failed');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const tokens = await response.json();
|
|
146
|
+
return {
|
|
147
|
+
accessToken: tokens.accessToken,
|
|
148
|
+
refreshToken: tokens.refreshToken,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
// Optional: Custom error handlers (only add interceptors if provided)
|
|
153
|
+
onUnauthorized: exchange => {
|
|
154
|
+
console.error('Unauthorized access:', exchange.request.url);
|
|
155
|
+
// Redirect to login or handle as needed
|
|
156
|
+
window.location.href = '/login';
|
|
157
|
+
},
|
|
158
|
+
onForbidden: async exchange => {
|
|
159
|
+
console.error('Forbidden access:', exchange.request.url);
|
|
160
|
+
// Show permission error
|
|
161
|
+
alert('You do not have permission to access this resource');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Apply all CoSec interceptors with one call
|
|
166
|
+
configurer.applyTo(fetcher);
|
|
167
|
+
|
|
168
|
+
// Now you can use the fetcher with full CoSec authentication
|
|
169
|
+
const response = await fetcher.get('/protected-endpoint');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Benefits of CoSecConfigurer
|
|
173
|
+
|
|
174
|
+
- ✅ **One-line setup**: `configurer.applyTo(fetcher)` configures everything
|
|
175
|
+
- ✅ **Minimal configuration**: Only `appId` and `tokenRefresher` are required
|
|
176
|
+
- ✅ **Sensible defaults**: Automatic error handling and parameter names
|
|
177
|
+
- ✅ **Type-safe**: Full TypeScript support with intelligent defaults
|
|
178
|
+
- ✅ **Backward compatible**: Original manual setup still works
|
|
179
|
+
|
|
115
180
|
## 🔧 Configuration
|
|
116
181
|
|
|
117
182
|
### CoSecOptions Interface
|
|
@@ -163,6 +228,45 @@ The interceptor automatically adds the following headers to requests:
|
|
|
163
228
|
|
|
164
229
|
### Core Classes
|
|
165
230
|
|
|
231
|
+
#### CoSecConfigurer
|
|
232
|
+
|
|
233
|
+
The recommended way to configure CoSec authentication. Provides a simplified API that automatically creates and configures all necessary interceptors and dependencies.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const configurer = new CoSecConfigurer({
|
|
237
|
+
appId: 'your-app-id',
|
|
238
|
+
tokenRefresher: {
|
|
239
|
+
refresh: async token => {
|
|
240
|
+
// Your token refresh implementation
|
|
241
|
+
return {
|
|
242
|
+
accessToken: 'new-access-token',
|
|
243
|
+
refreshToken: 'new-refresh-token',
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
// Optional error handlers (interceptors only added if provided)
|
|
248
|
+
onUnauthorized: exchange => {
|
|
249
|
+
/* handle 401 */
|
|
250
|
+
},
|
|
251
|
+
onForbidden: async exchange => {
|
|
252
|
+
/* handle 403 */
|
|
253
|
+
},
|
|
254
|
+
tenantId: 'tenantId', // default: 'tenantId'
|
|
255
|
+
ownerId: 'ownerId', // default: 'ownerId'
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
configurer.applyTo(fetcher);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Automatically Configured Interceptors:**
|
|
262
|
+
|
|
263
|
+
- `CoSecRequestInterceptor` - Adds CoSec headers
|
|
264
|
+
- `AuthorizationRequestInterceptor` - Adds Bearer token
|
|
265
|
+
- `ResourceAttributionRequestInterceptor` - Adds tenant/owner parameters
|
|
266
|
+
- `AuthorizationResponseInterceptor` - Handles token refresh
|
|
267
|
+
- `UnauthorizedErrorInterceptor` - Handles 401 errors
|
|
268
|
+
- `ForbiddenErrorInterceptor` - Handles 403 errors
|
|
269
|
+
|
|
166
270
|
#### AuthorizationRequestInterceptor
|
|
167
271
|
|
|
168
272
|
Automatically adds CoSec authentication headers to outgoing HTTP requests.
|
package/README.zh-CN.md
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
- **⚡ 性能优化**:最小开销,支持连接池和缓存
|
|
27
27
|
- **🛠️ TypeScript 优先**:完整类型定义,严格类型安全
|
|
28
28
|
- **🔌 可插拔架构**:模块化设计,易于集成和定制
|
|
29
|
+
- **⚙️ 简化配置**:使用 `CoSecConfigurer` 的一行设置,最小化配置开销
|
|
29
30
|
|
|
30
31
|
## 🚀 快速开始
|
|
31
32
|
|
|
@@ -112,6 +113,70 @@ fetcher.interceptors.response.use(
|
|
|
112
113
|
);
|
|
113
114
|
```
|
|
114
115
|
|
|
116
|
+
## 🚀 简化设置(推荐)
|
|
117
|
+
|
|
118
|
+
为了获得更简单的设置体验,请使用 `CoSecConfigurer` 类,它会自动处理所有复杂的依赖创建和拦截器配置:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
122
|
+
import { CoSecConfigurer } from '@ahoo-wang/fetcher-cosec';
|
|
123
|
+
|
|
124
|
+
// 创建 Fetcher 实例
|
|
125
|
+
const fetcher = new Fetcher({
|
|
126
|
+
baseURL: 'https://api.example.com',
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// 使用最少的必需配置创建 CoSec 配置器
|
|
130
|
+
const configurer = new CoSecConfigurer({
|
|
131
|
+
appId: 'your-app-id',
|
|
132
|
+
tokenRefresher: {
|
|
133
|
+
refresh: async token => {
|
|
134
|
+
// 实现您的令牌刷新逻辑
|
|
135
|
+
const response = await fetch('/api/auth/refresh', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify({ refreshToken: token.refreshToken }),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
throw new Error('Token refresh failed');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const tokens = await response.json();
|
|
146
|
+
return {
|
|
147
|
+
accessToken: tokens.accessToken,
|
|
148
|
+
refreshToken: tokens.refreshToken,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
// 可选:自定义错误处理器(仅在提供时才添加拦截器)
|
|
153
|
+
onUnauthorized: exchange => {
|
|
154
|
+
console.error('未授权访问:', exchange.request.url);
|
|
155
|
+
// 重定向到登录或根据需要处理
|
|
156
|
+
window.location.href = '/login';
|
|
157
|
+
},
|
|
158
|
+
onForbidden: async exchange => {
|
|
159
|
+
console.error('禁止访问:', exchange.request.url);
|
|
160
|
+
// 显示权限错误
|
|
161
|
+
alert('您没有权限访问此资源');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// 使用一次调用应用所有 CoSec 拦截器
|
|
166
|
+
configurer.applyTo(fetcher);
|
|
167
|
+
|
|
168
|
+
// 现在您可以使用具有完整 CoSec 认证的 fetcher
|
|
169
|
+
const response = await fetcher.get('/protected-endpoint');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### CoSecConfigurer 的优势
|
|
173
|
+
|
|
174
|
+
- ✅ **一行设置**:`configurer.applyTo(fetcher)` 配置一切
|
|
175
|
+
- ✅ **最小配置**:仅需要 `appId` 和 `tokenRefresher`
|
|
176
|
+
- ✅ **合理的默认值**:自动错误处理和参数名称
|
|
177
|
+
- ✅ **类型安全**:完整的 TypeScript 支持和智能默认值
|
|
178
|
+
- ✅ **向后兼容**:原始手动设置仍然有效
|
|
179
|
+
|
|
115
180
|
## 🔧 配置
|
|
116
181
|
|
|
117
182
|
### CoSecOptions 接口
|
|
@@ -163,6 +228,45 @@ interface JwtTokenManagerCapable {
|
|
|
163
228
|
|
|
164
229
|
### 核心类
|
|
165
230
|
|
|
231
|
+
#### CoSecConfigurer
|
|
232
|
+
|
|
233
|
+
配置 CoSec 认证的推荐方式。提供简化的 API,自动创建和配置所有必要的拦截器和依赖项。
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const configurer = new CoSecConfigurer({
|
|
237
|
+
appId: 'your-app-id',
|
|
238
|
+
tokenRefresher: {
|
|
239
|
+
refresh: async token => {
|
|
240
|
+
// 您的令牌刷新实现
|
|
241
|
+
return {
|
|
242
|
+
accessToken: 'new-access-token',
|
|
243
|
+
refreshToken: 'new-refresh-token',
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
// 可选错误处理器(仅在提供时才添加拦截器)
|
|
248
|
+
onUnauthorized: exchange => {
|
|
249
|
+
/* 处理 401 */
|
|
250
|
+
},
|
|
251
|
+
onForbidden: async exchange => {
|
|
252
|
+
/* 处理 403 */
|
|
253
|
+
},
|
|
254
|
+
tenantId: 'tenantId', // 默认: 'tenantId'
|
|
255
|
+
ownerId: 'ownerId', // 默认: 'ownerId'
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
configurer.applyTo(fetcher);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**自动配置的拦截器:**
|
|
262
|
+
|
|
263
|
+
- `CoSecRequestInterceptor` - 添加 CoSec 头部
|
|
264
|
+
- `AuthorizationRequestInterceptor` - 添加 Bearer 令牌
|
|
265
|
+
- `ResourceAttributionRequestInterceptor` - 添加租户/所有者参数
|
|
266
|
+
- `AuthorizationResponseInterceptor` - 处理令牌刷新
|
|
267
|
+
- `UnauthorizedErrorInterceptor` - 处理 401 错误
|
|
268
|
+
- `ForbiddenErrorInterceptor` - 处理 403 错误
|
|
269
|
+
|
|
166
270
|
#### AuthorizationRequestInterceptor
|
|
167
271
|
|
|
168
272
|
自动向传出 HTTP 请求添加 CoSec 认证头部。
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Fetcher, FetcherConfigurer, FetchExchange } from '@ahoo-wang/fetcher';
|
|
2
|
+
import { DeviceIdStorage } from './deviceIdStorage';
|
|
3
|
+
import { JwtTokenManager } from './jwtTokenManager';
|
|
4
|
+
import { TokenRefresher } from './tokenRefresher';
|
|
5
|
+
import { TokenStorage } from './tokenStorage';
|
|
6
|
+
/**
|
|
7
|
+
* Simplified configuration interface for CoSec setup.
|
|
8
|
+
* Only requires the essential configuration, with sensible defaults for everything else.
|
|
9
|
+
*/
|
|
10
|
+
export interface CoSecConfig {
|
|
11
|
+
/**
|
|
12
|
+
* Application ID to be sent in the CoSec-App-Id header.
|
|
13
|
+
* This is required for identifying your application in the CoSec system.
|
|
14
|
+
*/
|
|
15
|
+
appId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Token refresher implementation for handling expired tokens.
|
|
18
|
+
* This is required to enable automatic token refresh functionality.
|
|
19
|
+
*/
|
|
20
|
+
tokenRefresher: TokenRefresher;
|
|
21
|
+
/**
|
|
22
|
+
* Callback function invoked when an unauthorized (401) response is detected.
|
|
23
|
+
* If not provided, defaults to throwing an error.
|
|
24
|
+
*/
|
|
25
|
+
onUnauthorized?: (exchange: FetchExchange) => Promise<void> | void;
|
|
26
|
+
/**
|
|
27
|
+
* Callback function invoked when a forbidden (403) response is detected.
|
|
28
|
+
* If not provided, 403 errors will not be intercepted.
|
|
29
|
+
*/
|
|
30
|
+
onForbidden?: (exchange: FetchExchange) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* CoSecConfigurer provides a simplified way to configure all CoSec interceptors
|
|
34
|
+
* and dependencies with a single configuration object.
|
|
35
|
+
*
|
|
36
|
+
* This class automatically creates all necessary dependencies (TokenStorage, DeviceIdStorage,
|
|
37
|
+
* JwtTokenManager) and configures all CoSec interceptors with sensible defaults.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const configurer = new CoSecConfigurer({
|
|
42
|
+
* appId: 'my-app-001',
|
|
43
|
+
* tokenRefresher: {
|
|
44
|
+
* refresh: async (token: CompositeToken) => {
|
|
45
|
+
* // Your token refresh logic here
|
|
46
|
+
* const response = await fetch('/api/auth/refresh', {
|
|
47
|
+
* method: 'POST',
|
|
48
|
+
* body: JSON.stringify({ refreshToken: token.refreshToken }),
|
|
49
|
+
* });
|
|
50
|
+
* const newTokens = await response.json();
|
|
51
|
+
* return {
|
|
52
|
+
* accessToken: newTokens.accessToken,
|
|
53
|
+
* refreshToken: newTokens.refreshToken,
|
|
54
|
+
* };
|
|
55
|
+
* },
|
|
56
|
+
* },
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* configurer.applyTo(fetcher);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare class CoSecConfigurer implements FetcherConfigurer {
|
|
63
|
+
readonly config: CoSecConfig;
|
|
64
|
+
readonly tokenStorage: TokenStorage;
|
|
65
|
+
readonly deviceIdStorage: DeviceIdStorage;
|
|
66
|
+
readonly tokenManager: JwtTokenManager;
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new CoSecConfigurer instance with the provided configuration.
|
|
69
|
+
*
|
|
70
|
+
* @param config - Simplified CoSec configuration
|
|
71
|
+
*/
|
|
72
|
+
constructor(config: CoSecConfig);
|
|
73
|
+
/**
|
|
74
|
+
* Applies all CoSec interceptors to the provided Fetcher instance.
|
|
75
|
+
*
|
|
76
|
+
* This method configures the following interceptors in the correct order:
|
|
77
|
+
* 1. CoSecRequestInterceptor - Adds CoSec headers (appId, deviceId, requestId)
|
|
78
|
+
* 2. AuthorizationRequestInterceptor - Adds Authorization header with Bearer token
|
|
79
|
+
* 3. ResourceAttributionRequestInterceptor - Adds tenant/owner path parameters
|
|
80
|
+
* 4. AuthorizationResponseInterceptor - Handles 401 responses with token refresh
|
|
81
|
+
* 5. UnauthorizedErrorInterceptor - Handles unauthorized errors
|
|
82
|
+
* 6. ForbiddenErrorInterceptor - Handles forbidden errors
|
|
83
|
+
*
|
|
84
|
+
* @param fetcher - The Fetcher instance to configure
|
|
85
|
+
*/
|
|
86
|
+
applyTo(fetcher: Fetcher): void;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=cosecConfigurer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cosecConfigurer.d.ts","sourceRoot":"","sources":["../src/cosecConfigurer.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAI/E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAE/B;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEnE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,eAAgB,YAAW,iBAAiB;aAU3B,MAAM,EAAE,WAAW;IAT/C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IAEvC;;;;OAIG;gBACyB,MAAM,EAAE,WAAW;IAY/C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CA0ChC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yCAAyC,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yCAAyC,CAAC;AACxD,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC"}
|