From f11564fa50ece011804e744bb9130897e48ffd6c Mon Sep 17 00:00:00 2001 From: asp_ly Date: Wed, 27 Nov 2024 23:25:09 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E6=88=90=E4=BA=86=E7=A7=9F?= =?UTF-8?q?=E6=88=B7header=E5=A4=B4=E9=AA=8C=E8=AF=81=202=E3=80=81jwt?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0=203=E3=80=81=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E4=BA=86=E5=89=8D=E4=B8=80=E4=B8=AA=E9=80=92=E5=BD=92?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/config/AppConfig.java | 56 +++++++++++++++++++ .../backend/common/config/WebConfig.java | 27 --------- .../common/interceptor/TenantInterceptor.java | 55 ++++++++++++++++++ .../security/config/SecurityConfig.java | 32 ++++------- .../common/utils/PasswordGenerator.java | 17 ++++++ .../qqchen/deploy/backend/entity/User.java | 3 - backend/src/main/resources/application.yml | 6 +- 7 files changed, 141 insertions(+), 55 deletions(-) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/common/config/AppConfig.java delete mode 100644 backend/src/main/java/com/qqchen/deploy/backend/common/config/WebConfig.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/common/utils/PasswordGenerator.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/config/AppConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/common/config/AppConfig.java new file mode 100644 index 00000000..09fe44da --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/config/AppConfig.java @@ -0,0 +1,56 @@ +package com.qqchen.deploy.backend.common.config; + +import com.qqchen.deploy.backend.common.interceptor.TenantInterceptor; +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.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +import java.util.Arrays; +import java.util.Collections; + +@Configuration +public class AppConfig { + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + // 允许所有来源 + configuration.setAllowedOrigins(Collections.singletonList("*")); + // 允许的请求方法 + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + // 允许的请求头 + configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With")); + // 暴露的响应头 + configuration.setExposedHeaders(Collections.singletonList("Authorization")); + // 允许携带凭证(注意:如果您设置了所有来源,要设置凭证可能会遇到问题) + configuration.setAllowCredentials(true); + // 设置预检最大有效期 + configuration.setMaxAge(3600L); + // URL 基于 CORS 配置源 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); // 针对所有路径注册 CORS 配置 + return source; + } + + @Bean + public WebMvcConfigurer webMvcConfigurer(TenantInterceptor tenantInterceptor) { + return new WebMvcConfigurer() { + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册 LocaleChangeInterceptor + LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("lang"); + registry.addInterceptor(localeChangeInterceptor); + + // 注册 TenantInterceptor + registry.addInterceptor(tenantInterceptor).addPathPatterns("/**"); // Ensures it intercepts all requests + } + }; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/config/WebConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/common/config/WebConfig.java deleted file mode 100644 index 16f933cb..00000000 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/config/WebConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.qqchen.deploy.backend.common.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; - -@Configuration -public class WebConfig implements WebMvcConfigurer { - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins("*") // 允许所有来源 - .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 - .allowedHeaders("*") // 允许所有header - .maxAge(3600); // 预检请求的有效期,单位为秒 - } - - @Override - public void addInterceptors(InterceptorRegistry registry) { - LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); - localeChangeInterceptor.setParamName("lang"); - registry.addInterceptor(localeChangeInterceptor); - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java b/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java new file mode 100644 index 00000000..9d6ded0c --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/interceptor/TenantInterceptor.java @@ -0,0 +1,55 @@ +package com.qqchen.deploy.backend.common.interceptor; + +import com.qqchen.deploy.backend.common.context.TenantContext; +import com.qqchen.deploy.backend.common.enums.ResponseCode; +import com.qqchen.deploy.backend.common.exception.BusinessException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.util.Arrays; +import java.util.List; + +@Component +public class TenantInterceptor implements HandlerInterceptor { + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + + // 不需要进行租户隔离的路径 + private final List excludePaths = Arrays.asList( +// "/api/v1/users/login", + "/api/system/tenants/list", + "/swagger-ui/**", + "/v3/api-docs/**" + ); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String path = request.getRequestURI(); + System.out.println("Intercepting path: " + path); // 添加日志 + // 如果是白名单路径,不进行租户校验 + if (isExcludePath(path)) { + TenantContext.clear(); + return true; + } + // 获取租户ID + String tenantId = request.getHeader("X-Devops-Tenant-Id"); + if (tenantId == null || tenantId.trim().isEmpty()) { + throw new BusinessException(ResponseCode.TENANT_NOT_FOUND); + } + TenantContext.setTenantId(tenantId); + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + TenantContext.clear(); + } + + private boolean isExcludePath(String path) { + return excludePaths.stream() + .anyMatch(pattern -> pathMatcher.match(pattern, path)); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java index b3f9ad3c..e000b998 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/security/config/SecurityConfig.java @@ -42,7 +42,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .cors(cors -> cors.configurationSource(corsConfigurationSource())) +// .cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) @@ -59,28 +59,16 @@ public class SecurityConfig { return http.build(); } - @Bean - public UserDetailsService userDetailsService() { - UserDetails user = User.withUsername("anonymous") - .password("{noop}") - .roles("ANONYMOUS") - .build(); - return new InMemoryUserDetailsManager(user); - } + //TODO 这里会导致无限递归循环报错 +// @Bean +// public UserDetailsService userDetailsService() { +// UserDetails user = User.withUsername("anonymous") +// .password("{noop}") +// .roles("ANONYMOUS") +// .build(); +// return new InMemoryUserDetailsManager(user); +// } - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("*")); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); - configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Tenant-ID")); - configuration.setExposedHeaders(Arrays.asList("Authorization", "X-Tenant-ID")); - configuration.setMaxAge(3600L); - - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } @Bean public PasswordEncoder passwordEncoder() { diff --git a/backend/src/main/java/com/qqchen/deploy/backend/common/utils/PasswordGenerator.java b/backend/src/main/java/com/qqchen/deploy/backend/common/utils/PasswordGenerator.java new file mode 100644 index 00000000..11d09779 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/common/utils/PasswordGenerator.java @@ -0,0 +1,17 @@ +package com.qqchen.deploy.backend.common.utils; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +public class PasswordGenerator { + public static void main(String[] args) { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + String rawPassword = "admin123"; + String encodedPassword = encoder.encode(rawPassword); + System.out.println("Raw password: " + rawPassword); + System.out.println("Encoded password: " + encodedPassword); + + // 验证密码 + boolean matches = encoder.matches(rawPassword, encodedPassword); + System.out.println("Password matches: " + matches); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java b/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java index 58bf03c0..4ea482a5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/entity/User.java @@ -43,9 +43,6 @@ public class User extends Entity { @Column(nullable = false) private Boolean enabled = true; - @Column(name = "dept_id") - private Long deptId; - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) @JsonIgnore @ToString.Exclude diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index ffd9f797..099b7eca 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -3,9 +3,9 @@ server: spring: datasource: - url: jdbc:mysql://127.0.0.1:3306/2024_11_24_platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true - username: root - password: root + url: jdbc:mysql://192.168.1.111:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true + username: deploy-ease-platform + password: qichen5210523 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: