From 1c936afe4c7f87679faf1c23bb71bba27de03470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=AF=E8=88=AA=E8=80=81=E9=BD=90?= <280645618@qq.com> Date: Sat, 7 Mar 2026 11:52:22 +0800 Subject: [PATCH] =?UTF-8?q?ai=E5=BC=95=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qihangerp/erp/config/SecurityConfig.java | 36 ++++++ .../qihangerp/erp/filter/UrlTokenFilter.java | 115 ++++++++++++++++++ .../cn/qihangerp/gateway/TokenFilter.java | 3 + .../JwtAuthenticationTokenFilter.java | 6 +- .../cn/qihangerp/security/TokenService.java | 3 + vue/src/assets/icons/svg/goods.svg | 1 + vue/src/settings.js | 5 +- vue/src/store/modules/app.js | 4 +- 8 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 api/ai-agent/src/main/java/cn/qihangerp/erp/config/SecurityConfig.java create mode 100644 api/ai-agent/src/main/java/cn/qihangerp/erp/filter/UrlTokenFilter.java create mode 100644 vue/src/assets/icons/svg/goods.svg diff --git a/api/ai-agent/src/main/java/cn/qihangerp/erp/config/SecurityConfig.java b/api/ai-agent/src/main/java/cn/qihangerp/erp/config/SecurityConfig.java new file mode 100644 index 00000000..5e77123e --- /dev/null +++ b/api/ai-agent/src/main/java/cn/qihangerp/erp/config/SecurityConfig.java @@ -0,0 +1,36 @@ +//package cn.qihangerp.erp.config; +// +//import cn.qihangerp.erp.filter.UrlTokenFilter; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +//import org.springframework.security.web.SecurityFilterChain; +//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +// +///** +// * Spring Security配置 +// * +// * @author qihang +// */ +//@Configuration +//@EnableWebSecurity +//public class SecurityConfig { +// @Autowired +// private UrlTokenFilter urlTokenFilter; +// +// @Bean +// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { +// http +// .csrf(AbstractHttpConfigurer::disable) +// .authorizeRequests(authorizeRequests -> +// authorizeRequests +// .anyRequest().permitAll() +// ) +// .addFilterBefore(urlTokenFilter, UsernamePasswordAuthenticationFilter.class); +// +// return http.build(); +// } +//} diff --git a/api/ai-agent/src/main/java/cn/qihangerp/erp/filter/UrlTokenFilter.java b/api/ai-agent/src/main/java/cn/qihangerp/erp/filter/UrlTokenFilter.java new file mode 100644 index 00000000..2af6d8fa --- /dev/null +++ b/api/ai-agent/src/main/java/cn/qihangerp/erp/filter/UrlTokenFilter.java @@ -0,0 +1,115 @@ +//package cn.qihangerp.erp.filter; +// +//import cn.qihangerp.common.AjaxResult; +//import cn.qihangerp.common.enums.HttpStatus; +//import cn.qihangerp.security.LoginUser; +//import cn.qihangerp.security.TokenService; +//import com.alibaba.fastjson2.JSON; +//import jakarta.servlet.FilterChain; +//import jakarta.servlet.ServletException; +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletRequestWrapper; +//import jakarta.servlet.http.HttpServletResponse; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.http.MediaType; +//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +//import org.springframework.security.core.context.SecurityContextHolder; +//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +//import org.springframework.stereotype.Component; +//import org.springframework.web.filter.OncePerRequestFilter; +// +//import java.io.IOException; +//import java.io.PrintWriter; +// +///** +// * token过滤器 从URL参数中获取token并验证有效性 +// * +// * @author qihang +// */ +//@Component +//public class UrlTokenFilter extends OncePerRequestFilter { +// @Autowired +// private TokenService tokenService; +// private Logger log = LoggerFactory.getLogger(getClass()); +// +// @Override +// protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) +// throws ServletException, IOException { +// // 从URL参数中获取token +// String token = request.getParameter("token"); +// String url = request.getRequestURI(); +// +// // 跳过登录等不需要token的请求 +// if (url.contains("/login") || url.contains("/captchaImage")) { +// chain.doFilter(request, response); +// return; +// } +// +// // 如果URL参数中没有token,尝试从header中获取(保持兼容性) +// if (token == null || token.isEmpty()) { +// token = request.getHeader("Authorization"); +// } +// +// // 验证token +// if (token != null && !token.isEmpty()) { +// // 移除Bearer前缀 +// if (token.startsWith("Bearer ")) { +// token = token.substring(7); +// } +// +// // 将token声明为final,以便内部类可以引用 +// final String finalToken = token; +// +// // 将token设置到请求的header中,以便TokenService能够正常工作 +// final HttpServletRequest modifiedRequest = new HttpServletRequestWrapper(request) { +// @Override +// public String getHeader(String name) { +// if ("Authorization".equals(name)) { +// return "Bearer " + finalToken; +// } +// return super.getHeader(name); +// } +// }; +// +// // 验证token并设置用户信息 +// try { +// LoginUser loginUser = tokenService.getLoginUser(modifiedRequest); +// if (loginUser != null) { +// tokenService.verifyToken(loginUser); +// UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); +// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(modifiedRequest)); +// SecurityContextHolder.getContext().setAuthentication(authenticationToken); +// chain.doFilter(modifiedRequest, response); +// return; +// } +// } catch (Exception e) { +// log.error("Token validation failed: {}", e.getMessage()); +// } +// } +// +// // token无效或不存在 +// fallback("授权过期!", response); +// } +// +// private void fallback(String message, HttpServletResponse response) { +// response.setCharacterEncoding("UTF-8"); +// response.setContentType(MediaType.APPLICATION_JSON_VALUE); +// PrintWriter writer = null; +// try { +// if (message == null) { +// message = "401 Forbidden"; +// } +// AjaxResult res = AjaxResult.error(HttpStatus.UNAUTHORIZED, message); +// writer = response.getWriter(); +// writer.append(JSON.toJSONString(res)); +// } catch (IOException e) { +// log.error(e.getMessage()); +// } finally { +// if (writer != null) { +// writer.close(); +// } +// } +// } +//} diff --git a/api/gateway/src/main/java/cn/qihangerp/gateway/TokenFilter.java b/api/gateway/src/main/java/cn/qihangerp/gateway/TokenFilter.java index 21ec7928..104444e5 100644 --- a/api/gateway/src/main/java/cn/qihangerp/gateway/TokenFilter.java +++ b/api/gateway/src/main/java/cn/qihangerp/gateway/TokenFilter.java @@ -23,6 +23,9 @@ public class TokenFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst(TOKEN_HEADER); + if(StringUtils.isEmpty(token)){ + token=exchange.getRequest().getQueryParams().getFirst("token"); + } System.out.println("Token:"+token); String url = exchange.getRequest().getURI().getPath(); System.out.println("intercept " + url); diff --git a/core/security/src/main/java/cn/qihangerp/security/JwtAuthenticationTokenFilter.java b/core/security/src/main/java/cn/qihangerp/security/JwtAuthenticationTokenFilter.java index 20e20d6f..a8b75e75 100644 --- a/core/security/src/main/java/cn/qihangerp/security/JwtAuthenticationTokenFilter.java +++ b/core/security/src/main/java/cn/qihangerp/security/JwtAuthenticationTokenFilter.java @@ -18,6 +18,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; @@ -43,7 +44,10 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // String token = exchange.getRequest().getHeaders().getFirst(TOKEN_HEADER); - String token = request.getHeader("Authorization"); +// String token = request.getHeader("Authorization"); +// if(StringUtils.isEmpty(token)){ +// token = request.getParameter("token"); +// } String url = request.getRequestURI(); // log.info("intercept " + url); // log.info("token: " + token); || request.getRequestURI().equals("/getInfo") || request.getRequestURI().equals("/logout") diff --git a/core/security/src/main/java/cn/qihangerp/security/TokenService.java b/core/security/src/main/java/cn/qihangerp/security/TokenService.java index 1de5825e..ee7da735 100644 --- a/core/security/src/main/java/cn/qihangerp/security/TokenService.java +++ b/core/security/src/main/java/cn/qihangerp/security/TokenService.java @@ -213,6 +213,9 @@ public class TokenService private String getToken(HttpServletRequest request) { String token = request.getHeader("Authorization"); + if(org.springframework.util.StringUtils.isEmpty(token)){ + token = request.getParameter("token"); + } if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { token = token.replace(Constants.TOKEN_PREFIX, ""); diff --git a/vue/src/assets/icons/svg/goods.svg b/vue/src/assets/icons/svg/goods.svg new file mode 100644 index 00000000..28249cf2 --- /dev/null +++ b/vue/src/assets/icons/svg/goods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vue/src/settings.js b/vue/src/settings.js index 816db9fc..e3b9b900 100644 --- a/vue/src/settings.js +++ b/vue/src/settings.js @@ -34,7 +34,10 @@ module.exports = { * 是否显示动态标题 */ dynamicTitle: false, - + /** + * 侧边栏默认状态 true:展开 false:收起 + */ + sidebarDefaultOpen: false, /** * @type {string | array} 'production' | ['production', 'development'] * @description Need show err logs component. diff --git a/vue/src/store/modules/app.js b/vue/src/store/modules/app.js index 3e22d1c1..fe8a559c 100644 --- a/vue/src/store/modules/app.js +++ b/vue/src/store/modules/app.js @@ -1,8 +1,8 @@ import Cookies from 'js-cookie' - +import defaultSettings from '@/settings' const state = { sidebar: { - opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, + opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : defaultSettings.sidebarDefaultOpen, withoutAnimation: false, hide: false },