@lobehub/chat 1.100.1 → 1.100.2
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/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.100.2](https://github.com/lobehub/lobe-chat/compare/v1.100.1...v1.100.2)
|
6
|
+
|
7
|
+
<sup>Released on **2025-07-18**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Fix webapi proxy with clerk.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### What's fixed
|
19
|
+
|
20
|
+
- **misc**: Fix webapi proxy with clerk, closes [#8479](https://github.com/lobehub/lobe-chat/issues/8479) ([7dd65f0](https://github.com/lobehub/lobe-chat/commit/7dd65f0))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
5
30
|
### [Version 1.100.1](https://github.com/lobehub/lobe-chat/compare/v1.100.0...v1.100.1)
|
6
31
|
|
7
32
|
<sup>Released on **2025-07-17**</sup>
|
package/changelog/v1.json
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.100.
|
3
|
+
"version": "1.100.2",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -1,9 +1,16 @@
|
|
1
1
|
import { AuthObject } from '@clerk/backend';
|
2
2
|
import { NextRequest } from 'next/server';
|
3
3
|
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
JWTPayload,
|
6
|
+
LOBE_CHAT_AUTH_HEADER,
|
7
|
+
LOBE_CHAT_OIDC_AUTH_HEADER,
|
8
|
+
OAUTH_AUTHORIZED,
|
9
|
+
enableClerk,
|
10
|
+
} from '@/const/auth';
|
5
11
|
import { ClerkAuth } from '@/libs/clerk-auth';
|
6
12
|
import { AgentRuntime, AgentRuntimeError, ChatCompletionErrorPayload } from '@/libs/model-runtime';
|
13
|
+
import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
|
7
14
|
import { ChatErrorType } from '@/types/fetch';
|
8
15
|
import { createErrorResponse } from '@/utils/errorResponse';
|
9
16
|
import { getJWTPayload } from '@/utils/server/jwt';
|
@@ -50,12 +57,26 @@ export const checkAuth =
|
|
50
57
|
|
51
58
|
jwtPayload = await getJWTPayload(authorization);
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
const oidcAuthorization = req.headers.get(LOBE_CHAT_OIDC_AUTH_HEADER);
|
61
|
+
let isUseOidcAuth = false;
|
62
|
+
if (!!oidcAuthorization) {
|
63
|
+
const oidc = await validateOIDCJWT(oidcAuthorization);
|
64
|
+
|
65
|
+
isUseOidcAuth = true;
|
66
|
+
|
67
|
+
jwtPayload = {
|
68
|
+
...jwtPayload,
|
69
|
+
userId: oidc.userId,
|
70
|
+
};
|
71
|
+
}
|
72
|
+
|
73
|
+
if (!isUseOidcAuth)
|
74
|
+
checkAuthMethod({
|
75
|
+
accessCode: jwtPayload.accessCode,
|
76
|
+
apiKey: jwtPayload.apiKey,
|
77
|
+
clerkAuth,
|
78
|
+
nextAuthAuthorized: oauthAuthorized,
|
79
|
+
});
|
59
80
|
} catch (e) {
|
60
81
|
const params = await options.params;
|
61
82
|
|
package/src/const/auth.ts
CHANGED
@@ -5,6 +5,7 @@ export const enableNextAuth = authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH;
|
|
5
5
|
export const enableAuth = enableClerk || enableNextAuth || false;
|
6
6
|
|
7
7
|
export const LOBE_CHAT_AUTH_HEADER = 'X-lobe-chat-auth';
|
8
|
+
export const LOBE_CHAT_OIDC_AUTH_HEADER = 'Oidc-Auth';
|
8
9
|
|
9
10
|
export const OAUTH_AUTHORIZED = 'X-oauth-authorized';
|
10
11
|
|
@@ -41,10 +41,7 @@ export const getJWKS = (): object => {
|
|
41
41
|
}
|
42
42
|
};
|
43
43
|
|
44
|
-
|
45
|
-
* 从环境变量中获取 JWKS 并提取第一个 RSA 密钥
|
46
|
-
*/
|
47
|
-
const getJWKSPublicKey = async () => {
|
44
|
+
const getVerificationKey = async () => {
|
48
45
|
try {
|
49
46
|
const jwksString = oidcEnv.OIDC_JWKS_KEY;
|
50
47
|
|
@@ -58,20 +55,32 @@ const getJWKSPublicKey = async () => {
|
|
58
55
|
throw new Error('JWKS 格式无效: 缺少或为空的 keys 数组');
|
59
56
|
}
|
60
57
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
if (!rsaKey) {
|
58
|
+
const privateRsaKey = jwks.keys.find((key: any) => key.alg === 'RS256' && key.kty === 'RSA');
|
59
|
+
if (!privateRsaKey) {
|
65
60
|
throw new Error('JWKS 中没有找到 RS256 算法的 RSA 密钥');
|
66
61
|
}
|
67
62
|
|
68
|
-
//
|
69
|
-
|
63
|
+
// 创建一个只包含公钥组件的“纯净”JWK对象。
|
64
|
+
// RSA公钥的关键字段是 kty, n, e。其他如 kid, alg, use 也是公共的。
|
65
|
+
const publicKeyJwk = {
|
66
|
+
alg: privateRsaKey.alg,
|
67
|
+
e: privateRsaKey.e,
|
68
|
+
kid: privateRsaKey.kid,
|
69
|
+
kty: privateRsaKey.kty,
|
70
|
+
n: privateRsaKey.n,
|
71
|
+
use: privateRsaKey.use,
|
72
|
+
};
|
73
|
+
|
74
|
+
// 移除任何可能存在的 undefined 字段,保持对象干净
|
75
|
+
Object.keys(publicKeyJwk).forEach(
|
76
|
+
(key) => (publicKeyJwk as any)[key] === undefined && delete (publicKeyJwk as any)[key],
|
77
|
+
);
|
70
78
|
|
71
|
-
|
79
|
+
// 现在,无论在哪个环境下,`importJWK` 都会将这个对象正确地识别为一个公钥。
|
80
|
+
return await importJWK(publicKeyJwk, 'RS256');
|
72
81
|
} catch (error) {
|
73
82
|
log('获取 JWKS 公钥失败: %O', error);
|
74
|
-
throw new Error(`JWKS
|
83
|
+
throw new Error(`JWKS 公key获取失败: ${(error as Error).message}`);
|
75
84
|
}
|
76
85
|
};
|
77
86
|
|
@@ -85,7 +94,7 @@ export const validateOIDCJWT = async (token: string) => {
|
|
85
94
|
log('开始验证 OIDC JWT token');
|
86
95
|
|
87
96
|
// 获取公钥
|
88
|
-
const publicKey = await
|
97
|
+
const publicKey = await getVerificationKey();
|
89
98
|
|
90
99
|
// 验证 JWT
|
91
100
|
const { payload } = await jwtVerify(token, publicKey, {
|
@@ -3,7 +3,13 @@ import debug from 'debug';
|
|
3
3
|
import { User } from 'next-auth';
|
4
4
|
import { NextRequest } from 'next/server';
|
5
5
|
|
6
|
-
import {
|
6
|
+
import {
|
7
|
+
JWTPayload,
|
8
|
+
LOBE_CHAT_AUTH_HEADER,
|
9
|
+
LOBE_CHAT_OIDC_AUTH_HEADER,
|
10
|
+
enableClerk,
|
11
|
+
enableNextAuth,
|
12
|
+
} from '@/const/auth';
|
7
13
|
import { oidcEnv } from '@/envs/oidc';
|
8
14
|
import { ClerkAuth, IClerkAuth } from '@/libs/clerk-auth';
|
9
15
|
import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
|
@@ -102,7 +108,7 @@ export const createLambdaContext = async (request: NextRequest): Promise<LambdaC
|
|
102
108
|
if (oidcEnv.ENABLE_OIDC) {
|
103
109
|
log('OIDC enabled, attempting OIDC authentication');
|
104
110
|
const standardAuthorization = request.headers.get('Authorization');
|
105
|
-
const oidcAuthToken = request.headers.get(
|
111
|
+
const oidcAuthToken = request.headers.get(LOBE_CHAT_OIDC_AUTH_HEADER);
|
106
112
|
log('Standard Authorization header: %s', standardAuthorization ? 'exists' : 'not found');
|
107
113
|
log('Oidc-Auth header: %s', oidcAuthToken ? 'exists' : 'not found');
|
108
114
|
|