|
@@ -1,13 +1,21 @@
|
|
|
package com.dragon.tj.portal.auth.config;
|
|
|
|
|
|
-import com.dragon.tj.portal.auth.service.*;
|
|
|
+import com.dragon.tj.portal.auth.module.hmac.HmacAuthenticationFilter;
|
|
|
+import com.dragon.tj.portal.auth.service.JwtTokenAuthenticationFilter;
|
|
|
+import com.dragon.tj.portal.auth.service.JwtTokenLogoutSuccessHandler;
|
|
|
+import com.dragon.tj.portal.auth.service.MyCasAuthenticationEntryPoint;
|
|
|
+import com.dragon.tj.portal.auth.service.MySimpleUrlAuthenticationSuccessHandler;
|
|
|
+import com.dragon.tj.portal.auth.service.MyUserDetailsByNameServiceWrapper;
|
|
|
+import com.dragon.tj.portal.auth.service.MyUserDetailsService;
|
|
|
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
|
|
|
import org.jasig.cas.client.validation.TicketValidator;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
-import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
|
|
|
import org.springframework.context.annotation.Bean;
|
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
+import org.springframework.http.HttpStatus;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
import org.springframework.security.authentication.ProviderManager;
|
|
|
import org.springframework.security.cas.ServiceProperties;
|
|
|
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
|
|
@@ -15,11 +23,17 @@ import org.springframework.security.cas.web.CasAuthenticationFilter;
|
|
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
|
|
+import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
|
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
|
+import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
|
+import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
|
|
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
|
|
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
|
+
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
@Configuration
|
|
|
@EnableWebSecurity
|
|
@@ -46,7 +60,7 @@ public class WebSecurityConfig {
|
|
|
private String casFailureUrl;
|
|
|
|
|
|
@Autowired
|
|
|
- private ServletWebServerApplicationContext context;
|
|
|
+ private JdbcTemplate jdbcTemplate;
|
|
|
|
|
|
@Autowired
|
|
|
private JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter;
|
|
@@ -57,39 +71,81 @@ public class WebSecurityConfig {
|
|
|
@Autowired
|
|
|
private JwtTokenLogoutSuccessHandler logoutSuccessHandler;
|
|
|
|
|
|
- private static StringBuilder whiteList = new StringBuilder();
|
|
|
- private static String whiteListSplit = ",";
|
|
|
+ private static final StringBuilder whiteList = new StringBuilder();
|
|
|
+ private static final String DELIMITER_COMMA = ",";
|
|
|
|
|
|
- /**
|
|
|
- *
|
|
|
- *白名单
|
|
|
- */
|
|
|
static {
|
|
|
- whiteList.append("/test/login" + whiteListSplit);
|
|
|
- whiteList.append("/file/**" + whiteListSplit);
|
|
|
+ // 白名单
|
|
|
+ whiteList.append("/test/login").append(DELIMITER_COMMA)
|
|
|
+ .append("/file/**").append(DELIMITER_COMMA);
|
|
|
}
|
|
|
|
|
|
@Bean
|
|
|
public WebSecurityCustomizer webSecurityCustomizer() {
|
|
|
-
|
|
|
return (web) -> web.ignoring()
|
|
|
// 认证成功后才会忽略
|
|
|
.antMatchers("/resources/**");
|
|
|
}
|
|
|
|
|
|
+ @Bean
|
|
|
+ public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
|
|
|
+ http
|
|
|
+ .antMatcher("/api/**")
|
|
|
+ // CSRF禁用,因为不使用session
|
|
|
+ .csrf(CsrfConfigurer::disable)
|
|
|
+ .authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
|
|
|
+ .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
|
+ .exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(globalAuthenticationEntryPoint()))
|
|
|
+ // 内置filters已经排序 FilterOrderRegistration.FilterOrderRegistration()
|
|
|
+ .addFilterBefore(hmacAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
|
|
|
+ return http.build();
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: 2024/7/17 sai Delete
|
|
|
+ public AuthenticationEntryPoint globalAuthenticationEntryPoint() {
|
|
|
+ return (request, response, authException) -> {
|
|
|
+ response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ response.setContentType(MediaType.APPLICATION_JSON.toString());
|
|
|
+ response.getWriter().write("{\"message:\":\"Global认证失败:" + authException.getMessage() + "\"}");
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ public AuthenticationEntryPoint apiAuthenticationEntryPoint() {
|
|
|
+ return (request, response, authException) -> {
|
|
|
+ response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ response.setContentType(MediaType.APPLICATION_JSON.toString());
|
|
|
+ response.getWriter().write("{\"message:\":\"认证失败:" + authException.getMessage() + "\"}");
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ public HmacAuthenticationFilter hmacAuthenticationFilter() {
|
|
|
+ // HmacAuthenticationFilter filter = new HmacAuthenticationFilter("/api/token");
|
|
|
+ HmacAuthenticationFilter filter = new HmacAuthenticationFilter("/api/**");
|
|
|
+ filter.setJdbcTemplate(jdbcTemplate);
|
|
|
+ filter.setAuthenticationFailureHandler(new AuthenticationEntryPointFailureHandler(apiAuthenticationEntryPoint()));
|
|
|
+ filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
|
|
|
+ SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
|
+ });
|
|
|
+ return filter;
|
|
|
+ }
|
|
|
|
|
|
@Bean
|
|
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
http
|
|
|
// CSRF禁用,因为不使用session
|
|
|
- .csrf().disable().cors()
|
|
|
+ .csrf().disable()
|
|
|
+ // Enable CORS
|
|
|
+ .cors()
|
|
|
.and()
|
|
|
.authorizeRequests()
|
|
|
- .antMatchers(whiteList.toString().split(whiteListSplit)).permitAll()
|
|
|
+ .antMatchers(whiteList.toString().split(DELIMITER_COMMA)).permitAll()
|
|
|
.anyRequest().authenticated()
|
|
|
.and()
|
|
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
|
|
.and()
|
|
|
+ // 因为CasAuthenticationFilter仅拦截/sso/login,所以未认证前访问其他url失败时都走到这个兜底的exception处理
|
|
|
.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(authenticationEntryPoint()))
|
|
|
.addFilter(casAuthenticationFilter())
|
|
|
.addFilterBefore(jwtTokenAuthenticationFilter, CasAuthenticationFilter.class)
|
|
@@ -110,13 +166,13 @@ public class WebSecurityConfig {
|
|
|
public CasAuthenticationFilter casAuthenticationFilter() {
|
|
|
CasAuthenticationFilter filter = new CasAuthenticationFilter();
|
|
|
filter.setFilterProcessesUrl(casFilterUrl);
|
|
|
- filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(casFailureUrl));
|
|
|
|
|
|
CasAuthenticationProvider casAuthenticationProvider = casAuthenticationProvider(userDetailsService);
|
|
|
filter.setAuthenticationManager(new ProviderManager(casAuthenticationProvider));
|
|
|
|
|
|
mySimpleUrlAuthenticationSuccessHandler.setDefaultTargetUrl(casTargetUrl);
|
|
|
filter.setAuthenticationSuccessHandler(mySimpleUrlAuthenticationSuccessHandler);
|
|
|
+ filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(casFailureUrl));
|
|
|
|
|
|
return filter;
|
|
|
}
|