diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java
index 9d03429..84d265e 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/WebUtil.java
@@ -124,6 +124,19 @@ public class WebUtil extends org.springframework.web.util.WebUtils {
return (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getRequest();
}
+ /**
+ * 获取 RequestUri
+ *
+ * @param request HttpServletRequest
+ * @return {RequestUri}
+ */
+ public static String getRequestURI(HttpServletRequest request) {
+ if (request == null) {
+ return StringPool.EMPTY;
+ }
+ return request.getRequestURI();
+ }
+
/**
* 返回json
*
diff --git a/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportAuthConfiguration.java b/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportAuthConfiguration.java
new file mode 100644
index 0000000..4cd7c05
--- /dev/null
+++ b/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportAuthConfiguration.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.report.config;
+
+import jakarta.servlet.Filter;
+import org.springblade.core.report.filter.UReportAuthFilter;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.annotation.Order;
+
+/**
+ * UReport认证配置类
+ *
+ * @author BladeX
+ */
+@Order
+@AutoConfiguration
+@ConditionalOnProperty(value = "report.auth", havingValue = "true", matchIfMissing = true)
+public class ReportAuthConfiguration {
+
+ @Bean
+ public FilterRegistrationBean uReportAuthFilter() {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>();
+ registration.setFilter(new UReportAuthFilter());
+ registration.addUrlPatterns("/ureport/*");
+ registration.setName("uReportAuthFilter");
+ registration.setOrder(1);
+ return registration;
+ }
+
+}
diff --git a/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java b/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java
index 6ec2d40..32a397f 100644
--- a/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java
+++ b/blade-starter-report/src/main/java/org/springblade/core/report/config/ReportConfiguration.java
@@ -18,6 +18,7 @@ package org.springblade.core.report.config;
import com.bstek.ureport.UReportPropertyPlaceholderConfigurer;
import com.bstek.ureport.console.UReportServlet;
import com.bstek.ureport.provider.report.ReportProvider;
+import jakarta.servlet.Servlet;
import org.springblade.core.report.props.ReportDatabaseProperties;
import org.springblade.core.report.props.ReportProperties;
import org.springblade.core.report.provider.DatabaseProvider;
@@ -32,8 +33,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.annotation.Order;
-import jakarta.servlet.Servlet;
-
/**
* UReport配置类
*
diff --git a/blade-starter-report/src/main/java/org/springblade/core/report/filter/UReportAuthFilter.java b/blade-starter-report/src/main/java/org/springblade/core/report/filter/UReportAuthFilter.java
new file mode 100644
index 0000000..1fbe215
--- /dev/null
+++ b/blade-starter-report/src/main/java/org/springblade/core/report/filter/UReportAuthFilter.java
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.report.filter;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.tool.utils.WebUtil;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * UReport 鉴权过滤器
+ *
+ *
处理 /ureport/* 路径的访问鉴权,放行前端资源文件
+ *
+ * @author BladeX
+ */
+@Slf4j
+public class UReportAuthFilter implements Filter {
+
+ /**
+ * 前端资源文件扩展名
+ */
+ private static final List STATIC_RESOURCE_EXTENSIONS = Arrays.asList(
+ ".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg",
+ ".woff", ".woff2", ".ttf", ".eot", ".map", ".html", ".htm"
+ );
+
+ /**
+ * 资源文件路径前缀
+ */
+ private static final String RESOURCE_PATH_PREFIX = "/ureport/res/ureport-asserts";
+
+ /**
+ * Session 中存储认证状态的键名
+ */
+ private static final String SESSION_AUTH_KEY = "UREPORT_AUTHENTICATED";
+
+ /**
+ * Session 中存储用户信息的键名
+ */
+ private static final String SESSION_USER_KEY = "UREPORT_USER_INFO";
+
+ /**
+ * Session 中存储用户主键的键名
+ */
+ private static final String SESSION_USER_ID = "UREPORT_USER_ID";
+
+ /**
+ * Session 超时时间,单位为秒
+ */
+ private static final Integer INTERVAL_TIME = 120 * 60;
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+ String requestURI = WebUtil.getRequestURI(httpRequest);
+ String requestIP = WebUtil.getIP(httpRequest);
+
+ // 检查是否为静态资源文件,如果是则直接放行
+ if (isStaticResource(requestURI)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // 验证用户是否已认证(优先检查 Session,再检查 Token)
+ if (!isAuthenticatedWithSession(httpRequest)) {
+ log.warn("未授权访问 UReport API: {}, IP: {}", requestURI, requestIP);
+ handleUnauthorized(httpResponse);
+ return;
+ }
+
+ // 验证通过放行请求
+ chain.doFilter(request, response);
+ }
+
+ /**
+ * 判断是否为静态资源文件
+ */
+ private boolean isStaticResource(String requestURI) {
+ // 检查是否为资源文件路径
+ if (requestURI.startsWith(RESOURCE_PATH_PREFIX)) {
+ return true;
+ }
+
+ // 检查文件扩展名
+ String lowerCaseURI = requestURI.toLowerCase();
+ return STATIC_RESOURCE_EXTENSIONS.stream()
+ .anyMatch(lowerCaseURI::endsWith);
+ }
+
+ /**
+ * 验证用户是否已认证(Session + Token 双重验证)
+ */
+ private boolean isAuthenticatedWithSession(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+
+ // 1. 优先检查 Session 认证状态
+ if (session != null && Boolean.TRUE.equals(session.getAttribute(SESSION_AUTH_KEY))) {
+ log.debug("Session 认证有效,用户: {}", session.getAttribute(SESSION_USER_KEY));
+ return true;
+ }
+
+ // 2. Session 无效,尝试 Token 认证
+ if (isTokenAuthenticated(request)) {
+ // Token 认证成功,建立 Session
+ establishSession(request);
+ log.info("Token 认证成功,已建立 Session 会话");
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Token 认证验证
+ */
+ private boolean isTokenAuthenticated(HttpServletRequest request) {
+ try {
+ Long userId = AuthUtil.getUserId(request);
+ return userId != null && userId > 0;
+ } catch (Exception e) {
+ log.debug("Token 认证失败: {}", e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 建立认证会话
+ */
+ private void establishSession(HttpServletRequest request) {
+ HttpSession session = request.getSession(true);
+
+ try {
+ String userAccount = AuthUtil.getUserAccount(request);
+ Long userId = AuthUtil.getUserId(request);
+
+ // 设置认证标记
+ session.setAttribute(SESSION_AUTH_KEY, true);
+ session.setAttribute(SESSION_USER_KEY, userAccount);
+ session.setAttribute(SESSION_USER_ID, userId);
+
+ // 设置 Session 超时时间(60分钟)
+ session.setMaxInactiveInterval(INTERVAL_TIME);
+
+ log.debug("建立 UReport 认证会话: 用户 {}, SessionID: {}", userAccount, session.getId());
+ } catch (Exception e) {
+ log.warn("建立认证会话失败: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * 从 Session 获取用户账号
+ */
+ private String getUserFromSession(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ Object userAccount = session.getAttribute(SESSION_USER_KEY);
+ return userAccount != null ? userAccount.toString() : "未知用户";
+ }
+ return "未知用户";
+ }
+
+ /**
+ * 处理未授权访问
+ */
+ private void handleUnauthorized(HttpServletResponse response) throws IOException {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ response.setCharacterEncoding("UTF-8");
+
+ try (PrintWriter writer = response.getWriter()) {
+ writer.write("访问 UReport 需要 BladeX 的 Token 认证");
+ writer.flush();
+ }
+ }
+
+}
diff --git a/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java b/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java
index aceeb8d..0cf4455 100644
--- a/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java
+++ b/blade-starter-report/src/main/java/org/springblade/core/report/props/ReportProperties.java
@@ -28,6 +28,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "report")
public class ReportProperties {
private Boolean enabled = true;
+ private Boolean auth = true;
private Boolean disableHttpSessionReportCache = false;
private Boolean disableFileProvider = true;
private String fileStoreDir = StringPool.EMPTY;