1、完成了租户header头验证
2、jwt功能实现 3、解决了前一个递归调用的问题。
This commit is contained in:
parent
07c2d803b5
commit
f11564fa50
@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<String> 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));
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -43,9 +43,6 @@ public class User extends Entity<Long> {
|
||||
@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
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user