Spring 容器初始化時有打印出 JWT Secret 的值,但在實際調用時 base64Secret() 卻是 null
@Configuration
public class FilterConfig {
// 配置和注册自定义过滤器,用于拦截和处理特定路径的请求
@Bean
public FilterRegistrationBean<ServiceFilter> userTrackingFilter(ServiceFilter filter) {
FilterRegistrationBean<ServiceFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
// registrationBean.setFilter(new ServiceFilter(jwtProvider));
registrationBean.addUrlPatterns("/api/v1/cry/**");
registrationBean.setOrder(1);
return registrationBean;
}
}
@Slf4j
@Component
public class JwtProvider {
@Value("${jwt.secret}")
private String base64Secret;
@Value("${jwt.ttl}")
private long jwtExpiration;
@PostConstruct
public void init() {
log.info("JwtProvider initialized, base64Secret: {}", base64Secret);
if (base64Secret == null || base64Secret.isEmpty()) {
throw new RuntimeException("JWT Secret 未正確讀取!");
}
}
@PreDestroy
public void destroy() {
log.info("JwtProvider being destroyed, base64Secret: {}", base64Secret);
}
public Key getBase64Secret() {
try {
log.info("JwtProvider base64Secret:{}",base64Secret);
byte[] decodedKey = Base64.getDecoder().decode(base64Secret);
// log.info("decodedKey:{}",decodedKey);
return Keys.hmacShaKeyFor(decodedKey);
} catch (IllegalArgumentException e) {
throw new RuntimeException("JWT Secret 格式錯誤,請確保是 Base64 編碼", e);
}
}
package com.feddoubt.Cry.filter;
import com.feddoubt.common.Cry.config.jwt.JwtProvider;
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.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 正確方式關閉 CSRF
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/token", "/api/v1/key/public").permitAll() // 允許這些路徑不需要認證
.anyRequest().authenticated() // 其他 API 需要驗證
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 無狀態,使用 JWT
.addFilterBefore(new ServiceFilter(new JwtProvider()), UsernamePasswordAuthenticationFilter.class); // 加入 JWT 過濾器
return http.build();
}
}
.addFilterBefore(new ServiceFilter(new JwtProvider()) 這裡手動 new 了一個 JwtProvider 實例,這個新建的實例不是由 Spring 容器管理的,所以 @Value 注入就不會生效,導致 base64Secret 為 null。
修改後
package com.feddoubt.Cry.filter;
import com.feddoubt.common.Cry.config.jwt.JwtProvider;
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.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
private final JwtProvider jwtProvider;
private final ServiceFilter serviceFilter;
public SecurityConfig(JwtProvider jwtProvider, ServiceFilter serviceFilter) {
this.jwtProvider = jwtProvider;
this.serviceFilter = serviceFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 正確方式關閉 CSRF
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/token", "/api/v1/key/public").permitAll() // 允許這些路徑不需要認證
.anyRequest().authenticated() // 其他 API 需要驗證
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 無狀態,使用 JWT
.addFilterBefore(serviceFilter, UsernamePasswordAuthenticationFilter.class); // 加入 JWT 過濾器
return http.build();
}
}