create-skweb 3.4.0 → 3.5.0

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.
@@ -1,16 +1,17 @@
1
-
2
- > create-skweb@3.3.9 prebuild
3
- > tsc --outDir dist --rootDir src
4
-
5
-
6
- > create-skweb@3.3.9 build
7
- > rollup -c rollup.config.mjs && node scripts/inject-shebang.mjs && chmod +x dist/cli.js
8
-
9
- 
10
- src/index.ts → dist/index.js...
11
- (!) [plugin typescript] @rollup/plugin-typescript: outputToFilesystem option is defaulting to true.
12
- created dist/index.js in 391ms
13
- 
14
- src/cli.ts → dist/cli.js...
15
- created dist/cli.js in 214ms
16
- [inject-shebang] Shebang added to /Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/cli.js
1
+
2
+ > create-skweb@3.5.0 prebuild
3
+ > tsc --outDir dist --rootDir src
4
+
5
+ ⠙
6
+ > create-skweb@3.5.0 build
7
+ > rollup -c rollup.config.mjs && node scripts/inject-shebang.mjs && chmod +x dist/cli.js
8
+
9
+ ⠙
10
+ src/index.ts → dist/index.js...
11
+ (!) [plugin typescript] @rollup/plugin-typescript: outputToFilesystem option is defaulting to true.
12
+ created dist/index.js in 376ms
13
+ 
14
+ src/cli.ts → dist/cli.js...
15
+ created dist/cli.js in 239ms
16
+ [inject-shebang] Shebang added to /Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/cli.js
17
+ ⠙
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # create-skweb
2
2
 
3
+ ## 3.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a43c261: feat: 简化模板 auth/swagger 配置,添加 get-token 脚本
8
+
9
+ - Swagger 统一使用 bearerAuth (http + bearer + JWT),不再使用 oauth2 流程
10
+ - 移除 clientSecret 相关配置
11
+ - 添加 scripts/get-token.{js,ts}:从 Keycloak (ROPC grant) 获取 access token
12
+ - package.json 添加 get-token 脚本和 axios 依赖
13
+ - .env.example 添加 OIDC_CLIENT_ID/OIDC_USERNAME/OIDC_PASSWORD (供 get-token 使用)
14
+ - 所有三个模板(ts/mjs/cjs)已同步
15
+
3
16
  ## 3.3.9
4
17
 
5
18
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-skweb",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "Create a new SKWeb project with TypeScript, CJS, or MJS support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -44,7 +44,7 @@ SWAGGER_ENABLED=true
44
44
  JWT_SECRET=please-change-this-in-production
45
45
  JWT_EXPIRES_IN=7d
46
46
  {{else}}
47
- # ---------- Auth: jwks (OIDC compatible) ----------
47
+ # ---------- Auth: jwks (OIDC compatible, public-key signature) ----------
48
48
  # Works with any OIDC-compliant IdP. Common issuer formats:
49
49
  # Keycloak: https://kc.example.com/realms/myrealm
50
50
  # Auth0: https://your-tenant.auth0.com/
@@ -53,9 +53,15 @@ JWT_EXPIRES_IN=7d
53
53
  # `audience` is the client id of this API in the IdP (recommended).
54
54
  # JWKS URI is auto-derived as ${OIDC_ISSUER}/.well-known/jwks.json
55
55
  # unless OIDC_JWKS_URI is set explicitly.
56
+ # This API only verifies the JWT signature; it does not handle the OAuth flow.
57
+ # Use `npm run get-token` to obtain a token for local testing.
56
58
  OIDC_ISSUER=
57
59
  OIDC_AUDIENCE=
58
60
  OIDC_JWKS_URI=
61
+ # The following are read by scripts/get-token.js to fetch a test token:
62
+ OIDC_CLIENT_ID=
63
+ OIDC_USERNAME=
64
+ OIDC_PASSWORD=
59
65
  {{/if_eq}}
60
66
 
61
67
  # ---------- Logging ----------
@@ -13,6 +13,7 @@
13
13
  "cron:dev": "npx dotenvx run -- node --watch src/cron-app.js",
14
14
  "seed": "npx dotenvx run -- node src/commands/seed.js",
15
15
  "migrate": "npx dotenvx run -- node src/commands/migrate.js",
16
+ "get-token": "node scripts/get-token.js",
16
17
  "build": "cp -r src dist",
17
18
  "lint": "eslint --fix --ext .js src",
18
19
  "test": "npx dotenvx run -- mocha test/**/*.js",
@@ -21,6 +22,7 @@
21
22
  },
22
23
  "dependencies": {
23
24
  "@dotenvx/dotenvx": "^1.75.1",
25
+ "axios": "^1.7.7",
24
26
  "http-errors": "^2.0.1",
25
27
  "skweb-express": "^2.1.0",
26
28
  "skweb-express-jwt": "^3.0.0",
@@ -0,0 +1,58 @@
1
+ /**
2
+ * get-token.js
3
+ * -----------------------------------------------------------------------------
4
+ * Fetch a Keycloak access token using Resource Owner Password Credentials grant.
5
+ * Reads configuration from the project .env (via dotenv) and prints the token
6
+ * to stdout so you can pipe it into curl / paste it into Swagger UI.
7
+ *
8
+ * Required env vars in .env:
9
+ * OIDC_ISSUER - e.g. https://kc.example.com/realms/myrealm
10
+ * OIDC_CLIENT_ID - the public client id (must enable "Direct access grants")
11
+ * OIDC_USERNAME - the test user
12
+ * OIDC_PASSWORD - the test user's password
13
+ *
14
+ * Usage:
15
+ * node scripts/get-token.js
16
+ * TOKEN=$(node scripts/get-token.js)
17
+ * curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/users
18
+ */
19
+ 'use strict'
20
+
21
+ require('@dotenvx/dotenvx').config()
22
+
23
+ const axios = require('axios')
24
+
25
+ async function getToken() {
26
+ const issuer = (process.env.OIDC_ISSUER || '').replace(/\/$/, '')
27
+ const clientId = process.env.OIDC_CLIENT_ID
28
+ const username = process.env.OIDC_USERNAME
29
+ const password = process.env.OIDC_PASSWORD
30
+
31
+ if (!issuer) throw new Error('OIDC_ISSUER is missing in .env')
32
+ if (!clientId) throw new Error('OIDC_CLIENT_ID is missing in .env')
33
+ if (!username) throw new Error('OIDC_USERNAME is missing in .env')
34
+ if (!password) throw new Error('OIDC_PASSWORD is missing in .env')
35
+
36
+ const params = new URLSearchParams({
37
+ grant_type: 'password',
38
+ client_id: clientId,
39
+ username,
40
+ password
41
+ })
42
+
43
+ const tokenUrl = `${issuer}/protocol/openid-connect/token`
44
+ const response = await axios.post(tokenUrl, params.toString(), {
45
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
46
+ })
47
+
48
+ return response.data.access_token
49
+ }
50
+
51
+ getToken()
52
+ .then((token) => {
53
+ process.stdout.write(token + '\n')
54
+ })
55
+ .catch((err) => {
56
+ console.error('❌ Failed to fetch token:', err.response?.data || err.message)
57
+ process.exit(1)
58
+ })
@@ -7,13 +7,8 @@ const { SysUser } = require('../models/SysUser.js')
7
7
  * get:
8
8
  * summary: 获取用户列表
9
9
  * tags: [Users]
10
- * {{#if_eq auth "static"}}
11
10
  * security:
12
11
  * - bearerAuth: []
13
- * {{else}}
14
- * security:
15
- * - oidcAuth: []
16
- * {{/if_eq}}
17
12
  * parameters:
18
13
  * - in: query
19
14
  * name: page
@@ -50,13 +45,8 @@ const userList = {
50
45
  * get:
51
46
  * summary: 获取单个用户
52
47
  * tags: [Users]
53
- * {{#if_eq auth "static"}}
54
48
  * security:
55
49
  * - bearerAuth: []
56
- * {{else}}
57
- * security:
58
- * - oidcAuth: []
59
- * {{/if_eq}}
60
50
  * parameters:
61
51
  * - in: path
62
52
  * name: id
@@ -93,13 +83,8 @@ const userGet = {
93
83
  * post:
94
84
  * summary: 创建用户
95
85
  * tags: [Users]
96
- * {{#if_eq auth "static"}}
97
86
  * security:
98
87
  * - bearerAuth: []
99
- * {{else}}
100
- * security:
101
- * - oidcAuth: []
102
- * {{/if_eq}}
103
88
  * requestBody:
104
89
  * required: true
105
90
  * content:
@@ -141,13 +126,8 @@ const userCreate = {
141
126
  * put:
142
127
  * summary: 更新用户
143
128
  * tags: [Users]
144
- * {{#if_eq auth "static"}}
145
129
  * security:
146
130
  * - bearerAuth: []
147
- * {{else}}
148
- * security:
149
- * - oidcAuth: []
150
- * {{/if_eq}}
151
131
  * parameters:
152
132
  * - in: path
153
133
  * name: id
@@ -205,13 +185,8 @@ const userUpdate = {
205
185
  * delete:
206
186
  * summary: 删除用户
207
187
  * tags: [Users]
208
- * {{#if_eq auth "static"}}
209
188
  * security:
210
189
  * - bearerAuth: []
211
- * {{else}}
212
- * security:
213
- * - oidcAuth: []
214
- * {{/if_eq}}
215
190
  * parameters:
216
191
  * - in: path
217
192
  * name: id
@@ -19,44 +19,12 @@ function buildOpenApiSpec() {
19
19
  ],
20
20
  components: {
21
21
  securitySchemes: {
22
- {{#if_eq auth "static"}}
23
22
  bearerAuth: {
24
23
  type: 'http',
25
24
  scheme: 'bearer',
26
- bearerFormat: 'JWT'
25
+ bearerFormat: 'JWT',
26
+ description: 'Paste your JWT access token (use `npm run get-token` to fetch one).'
27
27
  }
28
- {{else}}
29
- oidcAuth: (() => {
30
- // Resolve OIDC endpoints from OIDC_ISSUER or OIDC_JWKS_URI
31
- // Supports Keycloak realms and generic OIDC providers
32
- const issuer = process.env.OIDC_ISSUER && process.env.OIDC_ISSUER.replace(/\/$/, '')
33
- const jwksUri = process.env.OIDC_JWKS_URI
34
- let baseUrl
35
- if (issuer) {
36
- baseUrl = issuer
37
- } else if (jwksUri) {
38
- // Keycloak JWKS URI: https://host/realms/<name>/protocol/openid-connect/certs
39
- const match = jwksUri.match(/^(https?:\/\/[^/]+\/realms\/[^/]+)/)
40
- if (match) baseUrl = match[1]
41
- }
42
- return {
43
- type: 'oauth2',
44
- flows: {
45
- authorizationCode: {
46
- authorizationUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/auth` : undefined,
47
- tokenUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
48
- refreshUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
49
- scopes: {
50
- openid: 'OpenID Connect scope',
51
- profile: 'User profile',
52
- email: 'Email address',
53
- offline_access: 'Offline token refresh'
54
- }
55
- }
56
- }
57
- }
58
- })()
59
- {{/if_eq}}
60
28
  }
61
29
  }
62
30
  },
@@ -44,18 +44,24 @@ SWAGGER_ENABLED=true
44
44
  JWT_SECRET=please-change-this-in-production
45
45
  JWT_EXPIRES_IN=7d
46
46
  {{else}}
47
- # ---------- Auth: jwks (OIDC compatible) ----------
47
+ # ---------- Auth: jwks (OIDC compatible, public-key signature) ----------
48
48
  # Works with any OIDC-compliant IdP. Common issuer formats:
49
49
  # Keycloak: https://kc.example.com/realms/myrealm
50
50
  # Auth0: https://your-tenant.auth0.com/
51
- # Okta: https://your-domain.okta.com/oauth2/default
51
+ # Okta: https://your-domain.okta.com/oauth2/default
52
52
  # Authing: https://your-app.authing.cn/oauth2/default
53
53
  # `audience` is the client id of this API in the IdP (recommended).
54
54
  # JWKS URI is auto-derived as ${OIDC_ISSUER}/.well-known/jwks.json
55
55
  # unless OIDC_JWKS_URI is set explicitly.
56
+ # This API only verifies the JWT signature; it does not handle the OAuth flow.
57
+ # Use `npm run get-token` to obtain a token for local testing.
56
58
  OIDC_ISSUER=
57
59
  OIDC_AUDIENCE=
58
60
  OIDC_JWKS_URI=
61
+ # The following are read by scripts/get-token.js to fetch a test token:
62
+ OIDC_CLIENT_ID=
63
+ OIDC_USERNAME=
64
+ OIDC_PASSWORD=
59
65
  {{/if_eq}}
60
66
 
61
67
  # ---------- Logging ----------
@@ -13,6 +13,7 @@
13
13
  "cron:dev": "npx dotenvx run -- node --watch src/cron-app.js",
14
14
  "seed": "npx dotenvx run -- node src/commands/seed.js",
15
15
  "migrate": "npx dotenvx run -- node src/commands/migrate.js",
16
+ "get-token": "node scripts/get-token.js",
16
17
  "build": "cp -r src dist",
17
18
  "lint": "eslint --fix --ext .js src",
18
19
  "test": "npx dotenvx run -- mocha test/**/*.mjs",
@@ -21,6 +22,7 @@
21
22
  },
22
23
  "dependencies": {
23
24
  "@dotenvx/dotenvx": "^1.75.1",
25
+ "axios": "^1.7.7",
24
26
  "http-errors": "^2.0.1",
25
27
  "skweb-express": "^2.1.0",
26
28
  "skweb-express-jwt": "^3.0.0",
@@ -0,0 +1,55 @@
1
+ /**
2
+ * get-token.js
3
+ * -----------------------------------------------------------------------------
4
+ * Fetch a Keycloak access token using Resource Owner Password Credentials grant.
5
+ * Reads configuration from the project .env (via dotenv) and prints the token
6
+ * to stdout so you can pipe it into curl / paste it into Swagger UI.
7
+ *
8
+ * Required env vars in .env:
9
+ * OIDC_ISSUER - e.g. https://kc.example.com/realms/myrealm
10
+ * OIDC_CLIENT_ID - the public client id (must enable "Direct access grants")
11
+ * OIDC_USERNAME - the test user
12
+ * OIDC_PASSWORD - the test user's password
13
+ *
14
+ * Usage:
15
+ * node scripts/get-token.js
16
+ * TOKEN=$(node scripts/get-token.js)
17
+ * curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/users
18
+ */
19
+ import '@dotenvx/dotenvx/config.js'
20
+ import axios from 'axios'
21
+
22
+ async function getToken() {
23
+ const issuer = (process.env.OIDC_ISSUER || '').replace(/\/$/, '')
24
+ const clientId = process.env.OIDC_CLIENT_ID
25
+ const username = process.env.OIDC_USERNAME
26
+ const password = process.env.OIDC_PASSWORD
27
+
28
+ if (!issuer) throw new Error('OIDC_ISSUER is missing in .env')
29
+ if (!clientId) throw new Error('OIDC_CLIENT_ID is missing in .env')
30
+ if (!username) throw new Error('OIDC_USERNAME is missing in .env')
31
+ if (!password) throw new Error('OIDC_PASSWORD is missing in .env')
32
+
33
+ const params = new URLSearchParams({
34
+ grant_type: 'password',
35
+ client_id: clientId,
36
+ username,
37
+ password
38
+ })
39
+
40
+ const tokenUrl = `${issuer}/protocol/openid-connect/token`
41
+ const response = await axios.post(tokenUrl, params.toString(), {
42
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
43
+ })
44
+
45
+ return response.data.access_token
46
+ }
47
+
48
+ getToken()
49
+ .then((token) => {
50
+ process.stdout.write(token + '\n')
51
+ })
52
+ .catch((err) => {
53
+ console.error('❌ Failed to fetch token:', err.response?.data || err.message)
54
+ process.exit(1)
55
+ })
@@ -7,13 +7,8 @@ import { SysUser } from '../models/SysUser.js'
7
7
  * get:
8
8
  * summary: 获取用户列表
9
9
  * tags: [Users]
10
- * {{#if_eq auth "static"}}
11
10
  * security:
12
11
  * - bearerAuth: []
13
- * {{else}}
14
- * security:
15
- * - oidcAuth: []
16
- * {{/if_eq}}
17
12
  * parameters:
18
13
  * - in: query
19
14
  * name: page
@@ -50,13 +45,8 @@ const userList = {
50
45
  * get:
51
46
  * summary: 获取单个用户
52
47
  * tags: [Users]
53
- * {{#if_eq auth "static"}}
54
48
  * security:
55
49
  * - bearerAuth: []
56
- * {{else}}
57
- * security:
58
- * - oidcAuth: []
59
- * {{/if_eq}}
60
50
  * parameters:
61
51
  * - in: path
62
52
  * name: id
@@ -93,13 +83,8 @@ const userGet = {
93
83
  * post:
94
84
  * summary: 创建用户
95
85
  * tags: [Users]
96
- * {{#if_eq auth "static"}}
97
86
  * security:
98
87
  * - bearerAuth: []
99
- * {{else}}
100
- * security:
101
- * - oidcAuth: []
102
- * {{/if_eq}}
103
88
  * requestBody:
104
89
  * required: true
105
90
  * content:
@@ -141,13 +126,8 @@ const userCreate = {
141
126
  * put:
142
127
  * summary: 更新用户
143
128
  * tags: [Users]
144
- * {{#if_eq auth "static"}}
145
129
  * security:
146
130
  * - bearerAuth: []
147
- * {{else}}
148
- * security:
149
- * - oidcAuth: []
150
- * {{/if_eq}}
151
131
  * parameters:
152
132
  * - in: path
153
133
  * name: id
@@ -205,13 +185,8 @@ const userUpdate = {
205
185
  * delete:
206
186
  * summary: 删除用户
207
187
  * tags: [Users]
208
- * {{#if_eq auth "static"}}
209
188
  * security:
210
189
  * - bearerAuth: []
211
- * {{else}}
212
- * security:
213
- * - oidcAuth: []
214
- * {{/if_eq}}
215
190
  * parameters:
216
191
  * - in: path
217
192
  * name: id
@@ -21,44 +21,12 @@ export function buildOpenApiSpec() {
21
21
  ],
22
22
  components: {
23
23
  securitySchemes: {
24
- {{#if_eq auth "static"}}
25
24
  bearerAuth: {
26
25
  type: 'http',
27
26
  scheme: 'bearer',
28
- bearerFormat: 'JWT'
27
+ bearerFormat: 'JWT',
28
+ description: 'Paste your JWT access token (use `npm run get-token` to fetch one).'
29
29
  }
30
- {{else}}
31
- oidcAuth: (() => {
32
- // Resolve OIDC endpoints from OIDC_ISSUER or OIDC_JWKS_URI
33
- // Supports Keycloak realms and generic OIDC providers
34
- const issuer = process.env.OIDC_ISSUER?.replace(/\/$/, '')
35
- const jwksUri = process.env.OIDC_JWKS_URI
36
- let baseUrl
37
- if (issuer) {
38
- baseUrl = issuer
39
- } else if (jwksUri) {
40
- // Keycloak JWKS URI: https://host/realms/<name>/protocol/openid-connect/certs
41
- const match = jwksUri.match(/^(https?:\/\/[^/]+\/realms\/[^/]+)/)
42
- if (match) baseUrl = match[1]
43
- }
44
- return {
45
- type: 'oauth2',
46
- flows: {
47
- authorizationCode: {
48
- authorizationUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/auth` : undefined,
49
- tokenUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
50
- refreshUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
51
- scopes: {
52
- openid: 'OpenID Connect scope',
53
- profile: 'User profile',
54
- email: 'Email address',
55
- offline_access: 'Offline token refresh'
56
- }
57
- }
58
- }
59
- }
60
- })()
61
- {{/if_eq}}
62
30
  }
63
31
  }
64
32
  },
@@ -44,7 +44,7 @@ SWAGGER_ENABLED=true
44
44
  JWT_SECRET=please-change-this-in-production
45
45
  JWT_EXPIRES_IN=7d
46
46
  {{else}}
47
- # ---------- Auth: jwks (OIDC compatible) ----------
47
+ # ---------- Auth: jwks (OIDC compatible, public-key signature) ----------
48
48
  # Works with any OIDC-compliant IdP. Common issuer formats:
49
49
  # Keycloak: https://kc.example.com/realms/myrealm
50
50
  # Auth0: https://your-tenant.auth0.com/
@@ -53,9 +53,15 @@ JWT_EXPIRES_IN=7d
53
53
  # `audience` is the client id of this API in the IdP (recommended).
54
54
  # JWKS URI is auto-derived as ${OIDC_ISSUER}/.well-known/jwks.json
55
55
  # unless OIDC_JWKS_URI is set explicitly.
56
+ # This API only verifies the JWT signature; it does not handle the OAuth flow.
57
+ # Use `npm run get-token` to obtain a token for local testing.
56
58
  OIDC_ISSUER=
57
59
  OIDC_AUDIENCE=
58
60
  OIDC_JWKS_URI=
61
+ # The following are read by scripts/get-token.ts to fetch a test token:
62
+ OIDC_CLIENT_ID=
63
+ OIDC_USERNAME=
64
+ OIDC_PASSWORD=
59
65
  {{/if_eq}}
60
66
 
61
67
  # ---------- Logging ----------
@@ -13,6 +13,7 @@
13
13
  "cron:dev": "npx dotenvx run -- tsx watch src/cron-app.ts",
14
14
  "seed": "npx dotenvx run -- tsx src/commands/seed.ts",
15
15
  "migrate": "npx dotenvx run -- tsx src/commands/migrate.ts",
16
+ "get-token": "tsx scripts/get-token.ts",
16
17
  "build": "tsc && rollup -c rollup.config.mjs",
17
18
  "build:dev": "rollup -c rollup.config.mjs --environment NODE_ENV:development",
18
19
  "lint": "eslint --fix --ext .ts src",
@@ -23,6 +24,7 @@
23
24
  },
24
25
  "dependencies": {
25
26
  "@dotenvx/dotenvx": "^1.75.1",
27
+ "axios": "^1.7.7",
26
28
  "http-errors": "^2.0.1",
27
29
  "skweb-express": "^2.1.0",
28
30
  "skweb-express-jwt": "^3.0.0",
@@ -0,0 +1,55 @@
1
+ /**
2
+ * get-token.ts
3
+ * -----------------------------------------------------------------------------
4
+ * Fetch a Keycloak access token using Resource Owner Password Credentials grant.
5
+ * Reads configuration from the project .env (via dotenv) and prints the token
6
+ * to stdout so you can pipe it into curl / paste it into Swagger UI.
7
+ *
8
+ * Required env vars in .env:
9
+ * OIDC_ISSUER - e.g. https://kc.example.com/realms/myrealm
10
+ * OIDC_CLIENT_ID - the public client id (must enable "Direct access grants")
11
+ * OIDC_USERNAME - the test user
12
+ * OIDC_PASSWORD - the test user's password
13
+ *
14
+ * Usage:
15
+ * tsx scripts/get-token.ts
16
+ * TOKEN=$(tsx scripts/get-token.ts)
17
+ * curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/users
18
+ */
19
+ import '@dotenvx/dotenvx/config'
20
+ import axios from 'axios'
21
+
22
+ async function getToken(): Promise<string> {
23
+ const issuer = (process.env.OIDC_ISSUER || '').replace(/\/$/, '')
24
+ const clientId = process.env.OIDC_CLIENT_ID
25
+ const username = process.env.OIDC_USERNAME
26
+ const password = process.env.OIDC_PASSWORD
27
+
28
+ if (!issuer) throw new Error('OIDC_ISSUER is missing in .env')
29
+ if (!clientId) throw new Error('OIDC_CLIENT_ID is missing in .env')
30
+ if (!username) throw new Error('OIDC_USERNAME is missing in .env')
31
+ if (!password) throw new Error('OIDC_PASSWORD is missing in .env')
32
+
33
+ const params = new URLSearchParams({
34
+ grant_type: 'password',
35
+ client_id: clientId,
36
+ username,
37
+ password
38
+ })
39
+
40
+ const tokenUrl = `${issuer}/protocol/openid-connect/token`
41
+ const response = await axios.post(tokenUrl, params.toString(), {
42
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
43
+ })
44
+
45
+ return response.data.access_token
46
+ }
47
+
48
+ getToken()
49
+ .then((token) => {
50
+ process.stdout.write(token + '\n')
51
+ })
52
+ .catch((err) => {
53
+ console.error('❌ Failed to fetch token:', err.response?.data || err.message)
54
+ process.exit(1)
55
+ })
@@ -7,13 +7,8 @@ import { SysUser } from '../models/SysUser.js'
7
7
  * get:
8
8
  * summary: 获取用户列表
9
9
  * tags: [Users]
10
- * {{#if_eq auth "static"}}
11
10
  * security:
12
11
  * - bearerAuth: []
13
- * {{else}}
14
- * security:
15
- * - oidcAuth: []
16
- * {{/if_eq}}
17
12
  * parameters:
18
13
  * - in: query
19
14
  * name: page
@@ -50,13 +45,8 @@ const userList = {
50
45
  * get:
51
46
  * summary: 获取单个用户
52
47
  * tags: [Users]
53
- * {{#if_eq auth "static"}}
54
48
  * security:
55
49
  * - bearerAuth: []
56
- * {{else}}
57
- * security:
58
- * - oidcAuth: []
59
- * {{/if_eq}}
60
50
  * parameters:
61
51
  * - in: path
62
52
  * name: id
@@ -93,13 +83,8 @@ const userGet = {
93
83
  * post:
94
84
  * summary: 创建用户
95
85
  * tags: [Users]
96
- * {{#if_eq auth "static"}}
97
86
  * security:
98
87
  * - bearerAuth: []
99
- * {{else}}
100
- * security:
101
- * - oidcAuth: []
102
- * {{/if_eq}}
103
88
  * requestBody:
104
89
  * required: true
105
90
  * content:
@@ -141,13 +126,8 @@ const userCreate = {
141
126
  * put:
142
127
  * summary: 更新用户
143
128
  * tags: [Users]
144
- * {{#if_eq auth "static"}}
145
129
  * security:
146
130
  * - bearerAuth: []
147
- * {{else}}
148
- * security:
149
- * - oidcAuth: []
150
- * {{/if_eq}}
151
131
  * parameters:
152
132
  * - in: path
153
133
  * name: id
@@ -205,13 +185,8 @@ const userUpdate = {
205
185
  * delete:
206
186
  * summary: 删除用户
207
187
  * tags: [Users]
208
- * {{#if_eq auth "static"}}
209
188
  * security:
210
189
  * - bearerAuth: []
211
- * {{else}}
212
- * security:
213
- * - oidcAuth: []
214
- * {{/if_eq}}
215
190
  * parameters:
216
191
  * - in: path
217
192
  * name: id
@@ -21,44 +21,12 @@ export function buildOpenApiSpec(): object {
21
21
  ],
22
22
  components: {
23
23
  securitySchemes: {
24
- {{#if_eq auth "static"}}
25
24
  bearerAuth: {
26
25
  type: 'http',
27
26
  scheme: 'bearer',
28
- bearerFormat: 'JWT'
27
+ bearerFormat: 'JWT',
28
+ description: 'Paste your JWT access token (use `npm run get-token` to fetch one).'
29
29
  }
30
- {{else}}
31
- oidcAuth: (() => {
32
- // Resolve OIDC endpoints from OIDC_ISSUER or OIDC_JWKS_URI
33
- // Supports Keycloak realms and generic OIDC providers
34
- const issuer = process.env.OIDC_ISSUER?.replace(/\/$/, '')
35
- const jwksUri = process.env.OIDC_JWKS_URI
36
- let baseUrl: string | undefined
37
- if (issuer) {
38
- baseUrl = issuer
39
- } else if (jwksUri) {
40
- // Keycloak JWKS URI: https://host/realms/<name>/protocol/openid-connect/certs
41
- const match = jwksUri.match(/^(https?:\/\/[^/]+\/realms\/[^/]+)/)
42
- if (match) baseUrl = match[1]
43
- }
44
- return {
45
- type: 'oauth2',
46
- flows: {
47
- authorizationCode: {
48
- authorizationUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/auth` : undefined,
49
- tokenUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
50
- refreshUrl: baseUrl ? `${baseUrl}/protocol/openid-connect/token` : undefined,
51
- scopes: {
52
- openid: 'OpenID Connect scope',
53
- profile: 'User profile',
54
- email: 'Email address',
55
- offline_access: 'Offline token refresh'
56
- }
57
- }
58
- }
59
- }
60
- })()
61
- {{/if_eq}}
62
30
  }
63
31
  }
64
32
  },