diff --git a/server/skillhub-app/pom.xml b/server/skillhub-app/pom.xml
index aeeee7a3..6ee9bfbe 100644
--- a/server/skillhub-app/pom.xml
+++ b/server/skillhub-app/pom.xml
@@ -27,9 +27,9 @@
micrometer-registry-prometheus
- org.springdoc
- springdoc-openapi-starter-webmvc-ui
- 2.3.0
+ com.github.xiaoymin
+ knife4j-openapi3-jakarta-spring-boot-starter
+ 4.5.0
com.iflytek.skillhub
diff --git a/server/skillhub-app/src/main/resources/application-dev.yml b/server/skillhub-app/src/main/resources/application-dev.yml
index c4bf1e67..2817e39b 100644
--- a/server/skillhub-app/src/main/resources/application-dev.yml
+++ b/server/skillhub-app/src/main/resources/application-dev.yml
@@ -167,8 +167,17 @@ skillhub:
display-name: ${BOOTSTRAP_ADMIN_DISPLAY_NAME:Admin}
email: ${BOOTSTRAP_ADMIN_EMAIL:admin@skillhub.local}
+knife4j:
+ enable: true
+ setting:
+ language: zh_cn
+ swagger-model-name: SkillHub API
+
springdoc:
+ api-docs:
+ path: /v3/api-docs
swagger-ui:
+ path: /swagger-ui.html
config-url: /skillhub-server/v3/api-docs/swagger-config
url: /skillhub-server/v3/api-docs
disable-swagger-default-url: true
diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/policy/RouteSecurityPolicyRegistry.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/policy/RouteSecurityPolicyRegistry.java
index efbe121e..86f5d08e 100644
--- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/policy/RouteSecurityPolicyRegistry.java
+++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/policy/RouteSecurityPolicyRegistry.java
@@ -32,6 +32,9 @@ public class RouteSecurityPolicyRegistry {
RouteAuthorizationPolicy.permitAll(null, "/v3/api-docs/**"),
RouteAuthorizationPolicy.permitAll(null, "/swagger-ui/**"),
RouteAuthorizationPolicy.permitAll(null, "/swagger-ui.html"),
+ RouteAuthorizationPolicy.permitAll(null, "/doc.html"),
+ RouteAuthorizationPolicy.permitAll(null, "/webjars/**"),
+ RouteAuthorizationPolicy.permitAll(null, "/favicon.ico"),
RouteAuthorizationPolicy.permitAll(null, "/.well-known/**"),
RouteAuthorizationPolicy.roles(null, "/actuator/prometheus", "SUPER_ADMIN", "AUDITOR"),
RouteAuthorizationPolicy.authenticated(HttpMethod.GET, "/api/v1/skills/*/star"),
@@ -101,6 +104,8 @@ public class RouteSecurityPolicyRegistry {
ApiTokenPolicy.allow(null, "/actuator/health"),
ApiTokenPolicy.allow(null, "/v3/api-docs/**"),
ApiTokenPolicy.allow(null, "/swagger-ui/**"),
+ ApiTokenPolicy.allow(null, "/doc.html"),
+ ApiTokenPolicy.allow(null, "/webjars/**"),
ApiTokenPolicy.require(null, "/api/v1/tokens", "token:manage"),
ApiTokenPolicy.require(null, "/api/v1/tokens/**", "token:manage"),
ApiTokenPolicy.require(HttpMethod.DELETE, "/api/v1/skills/id/*", "skill:delete"),
diff --git a/web/nginx.conf.template b/web/nginx.conf.template
index 7589ba1f..64124fb7 100644
--- a/web/nginx.conf.template
+++ b/web/nginx.conf.template
@@ -10,64 +10,59 @@ server {
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
- location /skillhub-web/ {
- alias /usr/share/nginx/html/;
- try_files $uri $uri/ /skillhub-web/index.html;
+ # 静态资源和 SPA 路由
+ location / {
+ try_files $uri $uri/ /index.html;
}
- location /skillhub-web/api/ {
- proxy_pass ${SKILLHUB_API_UPSTREAM};
+ # API 代理到后端 server 服务
+ location /api/ {
+ proxy_pass ${SKILLHUB_API_UPSTREAM}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
- location /skillhub-web/oauth2/ {
- proxy_pass ${SKILLHUB_API_UPSTREAM};
+ location /oauth2/ {
+ proxy_pass ${SKILLHUB_API_UPSTREAM}/oauth2/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
- location /skillhub-web/login/oauth2/ {
- proxy_pass ${SKILLHUB_API_UPSTREAM};
+ location /login/oauth2/ {
+ proxy_pass ${SKILLHUB_API_UPSTREAM}/login/oauth2/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
- location /skillhub-web/.well-known/ {
- proxy_pass ${SKILLHUB_API_UPSTREAM};
+ location /.well-known/ {
+ proxy_pass ${SKILLHUB_API_UPSTREAM}/.well-known/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
- location /skillhub-web/assets/ {
- alias /usr/share/nginx/html/assets/;
+ location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
- location = /skillhub-web/registry/skill.md {
- alias /usr/share/nginx/html/registry/skill.md;
+ location = /registry/skill.md {
default_type text/plain;
add_header Content-Disposition "inline";
add_header X-Content-Type-Options "nosniff";
+ try_files $uri =404;
}
- location = /skillhub-web/runtime-config.js {
- alias /usr/share/nginx/html/runtime-config.js;
+ location = /runtime-config.js {
add_header Cache-Control "no-store";
+ try_files $uri =404;
}
location /nginx-health {
return 200 'ok';
add_header Content-Type text/plain;
}
-
- # 根路径重定向到子路径
- location = / {
- return 301 /skillhub-web/;
- }
}
diff --git a/web/src/bootstrap.ts b/web/src/bootstrap.ts
index 8c8ddc6c..8f14ae53 100644
--- a/web/src/bootstrap.ts
+++ b/web/src/bootstrap.ts
@@ -7,7 +7,8 @@
async function loadRuntimeConfig() {
await new Promise((resolve, reject) => {
const script = document.createElement('script')
- script.src = '/runtime-config.js'
+ const base = import.meta.env.BASE_URL || '/'
+ script.src = `${base}runtime-config.js`
script.async = false
script.onload = () => resolve()
script.onerror = () => reject(new Error('Failed to load runtime config'))