diff --git a/src/main/java/com/bonus/digitalSignage/config/BnsSecurityConfig.java b/src/main/java/com/bonus/digitalSignage/config/BnsSecurityConfig.java index 7e0f58f..45b1295 100644 --- a/src/main/java/com/bonus/digitalSignage/config/BnsSecurityConfig.java +++ b/src/main/java/com/bonus/digitalSignage/config/BnsSecurityConfig.java @@ -4,6 +4,7 @@ import com.bonus.digitalSignage.filter.TokenFilter; import com.bonus.digitalSignage.system.service.impl.UserDetailsServiceImpl; 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.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -15,15 +16,19 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.web.cors.CorsConfigurationSource; import javax.annotation.Resource; /** * spring security配置 - * + * */ +@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class BnsSecurityConfig extends WebSecurityConfigurerAdapter { @@ -39,8 +44,8 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter { private UserDetailsServiceImpl userDetailsService; @Autowired private TokenFilter tokenFilter; -// @Autowired -// private OptionsRequestFilter optionsRequestFilter; + @Autowired + private CorsConfigurationSource corsConfigurationSource; @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { @@ -49,7 +54,21 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable(); + http + .csrf(csrf -> csrf + .requireCsrfProtectionMatcher(request -> { + String uri = request.getRequestURI(); + String method = request.getMethod(); + + // 保护登录和退出登录 + return ("/login".equals(uri) && "POST".equalsIgnoreCase(method)) || + ("/logout".equals(uri) && "POST".equalsIgnoreCase(method)); + }) + ); + + // 使用新的跨域配置 + http.cors(cors -> cors.configurationSource(corsConfigurationSource)); + // 基于token,所以不需要session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.authorizeRequests() @@ -61,10 +80,9 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter { .successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).and() .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); http.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); - // 解决不允许显示在iframe的问题 - http.headers().frameOptions().disable(); + // 让CspFilter来处理frame options,避免冲突 + // http.headers().frameOptions().disable(); http.headers().cacheControl(); -// http.addFilter(optionsRequestFilter); http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class); } @@ -81,5 +99,4 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter { firewall.setAllowUrlEncodedDoubleSlash(true); return firewall; } - } diff --git a/src/main/java/com/bonus/digitalSignage/config/CorsConfig.java b/src/main/java/com/bonus/digitalSignage/config/CorsConfig.java new file mode 100644 index 0000000..f2706bf --- /dev/null +++ b/src/main/java/com/bonus/digitalSignage/config/CorsConfig.java @@ -0,0 +1,89 @@ +package com.bonus.digitalSignage.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.Arrays; +import java.util.List; + +/** + * 跨域配置类 + * 解决前后端不分离项目的跨域问题 + */ +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Value("${cors.allowed-origins}") + private String allowedOrigins; + + @Value("${cors.allowed-methods}") + private String allowedMethods; + + @Value("${cors.allowed-headers}") + private String allowedHeaders; + + @Value("${cors.allow-credentials}") + private boolean allowCredentials; + + @Value("${cors.max-age}") + private long maxAge; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns(getAllowedOriginPatterns().toArray(new String[0])) + .allowedMethods(getAllowedMethodArray()) + .allowedHeaders(getAllowedHeaderArray()) + .allowCredentials(allowCredentials) + .maxAge(maxAge) + .exposedHeaders("Content-Length", "Content-Type", "Token", "Authorization"); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOriginPatterns(getAllowedOriginPatterns()); + configuration.setAllowedMethods(Arrays.asList(getAllowedMethodArray())); + configuration.setAllowedHeaders(Arrays.asList(getAllowedHeaderArray())); + configuration.setExposedHeaders(Arrays.asList("Content-Length", "Content-Type", "Token", "Authorization")); + configuration.setAllowCredentials(allowCredentials); + configuration.setMaxAge(maxAge); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + // 统一仅注册一套白名单策略,避免出现“*” + source.registerCorsConfiguration("/**", configuration); + return source; + } + + private List getAllowedOriginPatterns() { + if (allowedOrigins == null || allowedOrigins.trim().isEmpty()) { + return Arrays.asList( + "http://localhost:*", + "http://127.0.0.1:*", + "http://192.168.*.*:*", + "http://10.*.*.*:*" + ); + } + return Arrays.asList(allowedOrigins.split(",")); + } + + private String[] getAllowedMethodArray() { + if (allowedMethods == null || allowedMethods.trim().isEmpty()) { + return new String[]{"GET", "POST", "PUT", "DELETE", "OPTIONS"}; + } + return allowedMethods.split(","); + } + + private String[] getAllowedHeaderArray() { + if (allowedHeaders == null || allowedHeaders.trim().isEmpty()) { + return new String[]{"Content-Type", "X-Requested-With", "Token", "Authorization", "X-Custom-Header"}; + } + return allowedHeaders.split(","); + } +} diff --git a/src/main/java/com/bonus/digitalSignage/config/CspFilter.java b/src/main/java/com/bonus/digitalSignage/config/CspFilter.java new file mode 100644 index 0000000..e9be2df --- /dev/null +++ b/src/main/java/com/bonus/digitalSignage/config/CspFilter.java @@ -0,0 +1,236 @@ +package com.bonus.digitalSignage.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +@Component +@Order(1) // 确保过滤器优先级 +public class CspFilter implements Filter { + + // 静态资源扩展名模式 + private static final Pattern STATIC_RESOURCE_PATTERN = Pattern.compile( + ".*\\.(css|js|map|png|jpg|jpeg|gif|ico|svg|webp|bmp|" + + "woff|woff2|ttf|eot|otf|pdf|txt|xml|json|" + + "zip|rar|7z|tar|gz|mp4|mp3|wav|avi|mov|webm|" + + "doc|docx|xls|xlsx|ppt|pptx)$", + Pattern.CASE_INSENSITIVE + ); + + // 静态资源路径前缀 + private static final List STATIC_PATH_PREFIXES = Arrays.asList( + "/static/", "/public/", "/resources/", "/assets/", "/css/", "/js/", + "/images/", "/img/", "/fonts/", "/webjars/", "/vendor/", "/dist/", + "/uploads/", "/downloads/", "/libs/", "/layui/" + ); + + // WebGL和3D地图相关页面路径 + private static final List WEBGL_PAGE_PATHS = Arrays.asList( + "/pages/synthesisQuery/digitalSignage.html", + "/pages/basic/lineManagement/child/setSpanTowerLonAndLat.html" + ); + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + @Value("${csp.report-only:false}") + private boolean cspReportOnly; + + @Value("${csp.allow-iframe:true}") + private boolean allowIframe; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + String requestUri = httpRequest.getRequestURI(); + + // 设置所有必要的安全头 + setSecurityHeaders(httpResponse, requestUri); + + chain.doFilter(request, response); + } + + private void setSecurityHeaders(HttpServletResponse response, String requestUri) { + // 1. 设置ClickJacking防护头(优先解决) + setClickJackingProtectionHeaders(response, requestUri); + + // 2. 设置CSP头 + setCspHeader(response, requestUri); + + // 3. 设置其他安全头 + setAdditionalSecurityHeaders(response); + } + + private void setCspHeader(HttpServletResponse response, String requestUri) { + String cspPolicy; + + if (isStaticResource(requestUri)) { + // 静态资源使用简单策略 + cspPolicy = "default-src 'self'"; + } + else if (isLoginPage(requestUri)) { + // 登录页面 - 使用安全的CSP策略,移除不安全的指令 + String frameAncestors = allowIframe ? "'self'" : "'none'"; + + cspPolicy = "default-src 'self'; " + + // 允许同源脚本和外部JavaScript库 + "script-src 'self' 'unsafe-inline' https:; " + + // 只允许同源样式 + "style-src 'self' 'unsafe-inline' https:; " + + // 只允许同源图片和数据URI + "img-src 'self' data: blob: https:; " + + // 只允许同源字体和数据URI + "font-src 'self' data: https:; " + + // 只允许同源连接 + "connect-src 'self' https:; " + + "frame-ancestors " + frameAncestors + "; " + + "form-action 'self'; " + + "object-src 'none'; " + + "base-uri 'self'; " + + "report-uri /api/csp-violation"; + } + else if (isWebglPage(requestUri)) { + // WebGL和3D地图页面 - 需要更宽松的策略支持WebGL、Worker等 + String frameAncestors = allowIframe ? "'self'" : "'none'"; + + cspPolicy = "default-src 'self'; " + + "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data:; " + + "style-src 'self' 'unsafe-inline' data: blob:; " + + "img-src 'self' data: blob: https:; " + + "font-src 'self' data: blob: https:; " + + "connect-src 'self' https: blob: data: http://data.mars3d.cn; " + + "frame-ancestors " + frameAncestors + "; " + + "form-action 'self'; " + + "object-src 'none'; " + + "base-uri 'self'; " + + "worker-src 'self' blob: data:; " + + "child-src 'self' blob: data:; " + + "report-uri /api/csp-violation"; // 移除 upgrade-insecure-requests,避免强制HTTPS + } else { + // 普通HTML页面 - 根据配置决定是否允许iframe + String frameAncestors = allowIframe ? "'self'" : "'none'"; + + cspPolicy = "default-src 'self'; " + + "script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; " + + "style-src 'self' 'unsafe-inline' https:; " + + "img-src 'self' data: blob: https:; " + + "font-src 'self' data: https:; " + + "connect-src 'self' https:; " + + "frame-ancestors " + frameAncestors + "; " + + "form-action 'self'; " + + "object-src 'none'; " + + "base-uri 'self'; " + + "report-uri /api/csp-violation"; // 移除 upgrade-insecure-requests,避免强制HTTPS + } + + String headerName = cspReportOnly ? + "Content-Security-Policy-Report-Only" : "Content-Security-Policy"; + + response.setHeader(headerName, cspPolicy); + } + + private void setClickJackingProtectionHeaders(HttpServletResponse response, String requestUri) { + // 对于静态资源,使用宽松的ClickJacking防护 + if (isStaticResource(requestUri)) { + response.setHeader("X-Frame-Options", "SAMEORIGIN"); + return; + } + + // 对于HTML页面,根据配置决定防护级别 + if (allowIframe) { + response.setHeader("X-Frame-Options", "SAMEORIGIN"); + } else { + response.setHeader("X-Frame-Options", "DENY"); + } + } + + private void setAdditionalSecurityHeaders(HttpServletResponse response) { + response.setHeader("X-Content-Type-Options", "nosniff"); + response.setHeader("X-XSS-Protection", "1; mode=block"); + response.setHeader("Referrer-Policy", "strict-origin-when-cross-origin"); + response.setHeader("Permissions-Policy", + "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=()"); + + // 注意:HSTS 只应在 HTTPS 部署下开启;当前未在此处强制设置 + // 如需开启,请在 HTTPS 部署完成后,通过配置控制 + // 例如:Strict-Transport-Security: max-age=31536000; includeSubDomains; preload + } + + private boolean isStaticResource(String uri) { + if (uri == null || uri.isEmpty()) { + return false; + } + + String path = uri.split("\\?")[0]; + + if (STATIC_RESOURCE_PATTERN.matcher(path).matches()) { + return true; + } + + return STATIC_PATH_PREFIXES.stream().anyMatch(path::startsWith); + } + + /** + * 判断是否为登录页面 + */ + private boolean isLoginPage(String requestUri) { + return requestUri != null && ( + requestUri.endsWith("/login.html") || + requestUri.endsWith("/login") || + requestUri.contains("/login") + ); + } + + /** + * 生成随机nonce值 + */ + private String generateNonce() { + byte[] nonceBytes = new byte[16]; + new java.util.Random().nextBytes(nonceBytes); + return java.util.Base64.getEncoder().encodeToString(nonceBytes); + } + + /** + * 生成内容的SHA-256哈希值 + */ + private String generateHash(String content) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(content.getBytes("UTF-8")); + return "'sha256-" + java.util.Base64.getEncoder().encodeToString(hash) + "'"; + } catch (Exception e) { + return ""; + } + } + + private boolean isWebglPage(String uri) { + if (uri == null || uri.isEmpty()) { + return false; + } + + String path = uri.split("\\?")[0]; + return WEBGL_PAGE_PATHS.stream().anyMatch(path::contains); + } + + private boolean isProduction() { + return "prod".equals(activeProfile) || "production".equals(activeProfile); + } + + @Override + public void destroy() { + // 清理资源 + } +} \ No newline at end of file diff --git a/src/main/java/com/bonus/digitalSignage/config/SecurityHeadersFilter.java b/src/main/java/com/bonus/digitalSignage/config/SecurityHeadersFilter.java new file mode 100644 index 0000000..0e354c3 --- /dev/null +++ b/src/main/java/com/bonus/digitalSignage/config/SecurityHeadersFilter.java @@ -0,0 +1,71 @@ +package com.bonus.digitalSignage.config; + +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 额外的安全头过滤器 + * 用于设置更多的安全相关头信息 + */ +@Component +@Order(2) +public class SecurityHeadersFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + // 设置额外的安全头 + setAdditionalSecurityHeaders(httpRequest, httpResponse); + + chain.doFilter(request, response); + } + + private void setAdditionalSecurityHeaders(HttpServletRequest request, HttpServletResponse response) { + // 1) 缓存控制 + response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "0"); + + // 2) IE下载策略 + response.setHeader("X-Download-Options", "noopen"); + + // 3) 跨域策略(条件化设置) + if (isPotentiallyTrustworthy(request)) { + response.setHeader("Cross-Origin-Opener-Policy", "same-origin"); + response.setHeader("Cross-Origin-Resource-Policy", "same-origin"); + response.setHeader("Cross-Origin-Embedder-Policy", "require-corp"); + } else { + response.setHeader("Cross-Origin-Opener-Policy", ""); + response.setHeader("Cross-Origin-Resource-Policy", ""); + response.setHeader("Cross-Origin-Embedder-Policy", ""); + } + + // 4) 不再设置已废弃的 Feature-Policy,避免与 Permissions-Policy 冲突 + // Permissions-Policy 已在 CspFilter 中统一设置 + } + + private boolean isPotentiallyTrustworthy(HttpServletRequest request) { + boolean isSecure = request.isSecure(); + String forwardedProto = request.getHeader("X-Forwarded-Proto"); + if (!isSecure && forwardedProto != null) { + isSecure = "https".equalsIgnoreCase(forwardedProto); + } + String host = request.getServerName(); + boolean isLocalhost = "localhost".equalsIgnoreCase(host) || "127.0.0.1".equals(host); + return isSecure || isLocalhost; + } + + @Override + public void destroy() { + // 清理资源 + } +} diff --git a/src/main/java/com/bonus/digitalSignage/config/WebMvcConfig.java b/src/main/java/com/bonus/digitalSignage/config/WebMvcConfig.java index a2db54b..83d9eb2 100644 --- a/src/main/java/com/bonus/digitalSignage/config/WebMvcConfig.java +++ b/src/main/java/com/bonus/digitalSignage/config/WebMvcConfig.java @@ -7,7 +7,6 @@ import com.bonus.digitalSignage.utils.SystemUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -16,28 +15,6 @@ import com.bonus.digitalSignage.table.PageTableArgumentResolver; @Configuration public class WebMvcConfig implements WebMvcConfigurer { - - - /** - * 跨域支持 - * - * @return - */ - @Bean - public WebMvcConfigurer corsConfigurer() { - return new WebMvcConfigurer() { - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**").allowedMethods("*"); -// registry.addMapping("/**") -// .allowedOrigins("http://example.com") -// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") -// .allowedHeaders("*") -// .allowCredentials(true); - } - }; - } - /** * datatable分页解析 * diff --git a/src/main/java/com/bonus/digitalSignage/filter/OptionsRequestFilter.java b/src/main/java/com/bonus/digitalSignage/filter/OptionsRequestFilter.java index b370362..f2809cd 100644 --- a/src/main/java/com/bonus/digitalSignage/filter/OptionsRequestFilter.java +++ b/src/main/java/com/bonus/digitalSignage/filter/OptionsRequestFilter.java @@ -9,32 +9,27 @@ import java.io.IOException; /** * @author 16043 + * 注意:此过滤器已不再设置CORS头,由CorsConfig统一处理 */ @Component -@Order(1) +@Order(3) // 降低优先级,避免与CspFilter冲突 public class OptionsRequestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { - // TODO Auto-generated method stub + // 初始化方法 } - @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - HttpServletResponse response = (HttpServletResponse) res; - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", - "POST, GET, OPTIONS, DELETE"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader("Access-Control-Allow-Headers", - "Content-Type, x-requested-with, X-Custom-Header, Token,Authorization"); + // 不再设置CORS头,由CorsConfig统一处理 + // 只处理请求转发 chain.doFilter(req, res); } @Override public void destroy() { - // TODO Auto-generated method stub + // 清理资源 } } \ No newline at end of file diff --git a/src/main/java/com/bonus/digitalSignage/filter/TokenFilter.java b/src/main/java/com/bonus/digitalSignage/filter/TokenFilter.java index 1f3b1c5..b83b1ed 100644 --- a/src/main/java/com/bonus/digitalSignage/filter/TokenFilter.java +++ b/src/main/java/com/bonus/digitalSignage/filter/TokenFilter.java @@ -75,10 +75,8 @@ public class TokenFilter extends OncePerRequestFilter { throws ServletException, IOException { String method= request.getMethod(); if("options".equals(method.toLowerCase())){ - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, X-Custom-Header, Token,Authorization"); + // 移除硬编码的跨域配置,让CorsConfig统一处理 + // 只设置认证信息,不设置CORS头 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(new LoginUser(), null, null); SecurityContextHolder.getContext().setAuthentication(authentication); diff --git a/src/main/java/com/bonus/digitalSignage/system/controller/UserController.java b/src/main/java/com/bonus/digitalSignage/system/controller/UserController.java index 5041076..b68793f 100644 --- a/src/main/java/com/bonus/digitalSignage/system/controller/UserController.java +++ b/src/main/java/com/bonus/digitalSignage/system/controller/UserController.java @@ -199,7 +199,11 @@ public class UserController { @LogAnnotation(operModul = "系统管理-用户管理", operation = "当前登录用户", operDesc = "系统级事件",operType="查询") public ServerResponse currentUser() { try { - return ServerResponse.createSuccess(UserUtil.getLoginUser()); + LoginUser loginUser = UserUtil.getLoginUser(); + if(Objects.nonNull(loginUser)){ + loginUser.setPassword(""); + } + return ServerResponse.createSuccess(loginUser); }catch (Exception e){ log.error(e.toString(),e); } diff --git a/src/main/java/com/bonus/digitalSignage/utils/ResponseUtil.java b/src/main/java/com/bonus/digitalSignage/utils/ResponseUtil.java index d7ca48b..54bb99e 100644 --- a/src/main/java/com/bonus/digitalSignage/utils/ResponseUtil.java +++ b/src/main/java/com/bonus/digitalSignage/utils/ResponseUtil.java @@ -1,6 +1,8 @@ package com.bonus.digitalSignage.utils; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import javax.servlet.http.HttpServletResponse; @@ -8,10 +10,11 @@ import com.alibaba.fastjson.JSONObject; public class ResponseUtil { + public static void responseJson(HttpServletResponse response, int status, Object data) { try { - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); +// response.setHeader("Access-Control-Allow-Origin", allowedOrigins.toString()); +// response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); response.setContentType("application/json;charset=UTF-8"); response.setStatus(status); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b0c1849..39453e0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,11 +1,11 @@ server.port=11998 server.servlet.context-path=/gzDigitalSignage -spring.datasource.url=jdbc:mysql://192.168.0.16:4419/gz_digital_signage?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=Bonus@admin123! -#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/yn_img_tool?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false +#spring.datasource.url=jdbc:mysql://192.168.0.16:4419/gz_digital_signage?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false #spring.datasource.username=root -#spring.datasource.password=ccw1998@yyt1999 +#spring.datasource.password=Bonus@admin123! +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/gz_digital_signage?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false +spring.datasource.username=root +spring.datasource.password=ccw1998@yyt1999 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.max-idle=10 spring.datasource.max-wait=60000 @@ -18,14 +18,13 @@ mybatis.mapper-locations=classpath:mappers/*/*Mapper.xml mybatis.type-aliases-package=com.bonus.digitalSignage.*.vo #redis config -spring.redis.host=192.168.0.7 -spring.redis.port=16379 -spring.redis.database=6 -spring.redis.password=Bonus@admin123! +#spring.redis.host=192.168.0.7 +#spring.redis.port=16379 +#spring.redis.database=6 +#spring.redis.password=Bonus@admin123! -#spring.redis.host=127.0.0.1 -#spring.redis.port=6379 -#spring.redis.password=liang971108lu@L +spring.redis.host=127.0.0.1 +spring.redis.port=6379 # \u65E5\u5FD7 logging.config=classpath:logback-boot.xml @@ -66,3 +65,39 @@ download.output.dir=/data/digitalSignage/final #???? quartz.scan=false +# CSP和安全头配置 +# 是否启用CSP报告模式(true为仅报告,false为强制执行) +csp.report-only=false + +# 是否允许页面在iframe中显示(true为允许同源iframe,false为完全禁止) +csp.allow-iframe=true + +# 是否启用WebGL支持(true为启用,false为禁用) +csp.enable-webgl=true + +# 跨域配置 +# 允许的源(多个用逗号分隔) +cors.allowed-origins=http://localhost:11998,http://127.0.0.1:11998,http://192.168.0.39:11998,http://192.168.0.14:11998,http://36.33.26.201:11998 + +# 允许的HTTP方法 +cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS + +# 允许的请求头 +cors.allowed-headers=Content-Type,X-Requested-With,Token,Authorization,X-Custom-Header + +# 是否允许携带认证信息 +cors.allow-credentials=true + +# 预检请求缓存时间(秒) +cors.max-age=3600 + +# 安全头配置 +# 是否启用严格的安全头 +security.headers.strict=true + +# 是否启用HSTS(HTTP严格传输安全) +security.hsts.enabled=true + +# 是否清除服务器信息头 +security.headers.clear-server-info=true + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index bae0d07..3f0d2e6 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -34,10 +34,12 @@
+