package ******;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @Author
* @Desc spring security 由于前後端分離是以伺服器端不能用session控制,通過基于 token機制 進行登陸驗證
*/
@SpringBootConfiguration
@EnableWebSecurity // 開啟WebSecurity支援
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityByTokenConfig {
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
public void setJwtAuthenticationTokenFilter(JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter) {
this.jwtAuthenticationTokenFilter = jwtAuthenticationTokenFilter;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return configure(http);
}
protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
http
// 開啟跨域
.cors().configurationSource(corsConfigurationSource())
.and()
.csrf()
.disable() // 禁用csrf保護
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用session
.and()
.headers().frameOptions().disable() //允許iframe通路
.and()
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> {
try {
authorizationManagerRequestMatcherRegistry
.requestMatchers("/login/**").permitAll() // 登入過濾
.requestMatchers("/static/**").permitAll() // 靜态資源
.anyRequest().fullyAuthenticated()
.and()
.exceptionHandling() // 異常處理
.authenticationEntryPoint(new RestAuthenticationEntryPoint()) // 未認證異常處理
.accessDeniedHandler(new SysAccessDeniedHandler()); // 權限拒絕異常處理
} catch (Exception e) {
throw new RuntimeException(e);
}
})
// 添加前置過濾器
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
//禁用header緩存
.headers().cacheControl();
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return new WebSecurityCustomizer() {
@Override
public void customize(WebSecurity web) {
web.ignoring().requestMatchers("/images/**", "/js/**", "/webjars/**");
}
};
}
/**
* 跨域配置
*
* @return
*/
private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
List<String> exposedHeaders = Arrays.asList("X-Authenticate", "Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type", "Date", "_token", "Token");
exposedHeaders.forEach(configuration::addExposedHeader);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}