package kr.co.uplus.ez.config; import javax.servlet.Filter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsUtils; import kr.co.uplus.ez.api.login.LoginFailureHandler; import kr.co.uplus.ez.api.login.LoginSuccessHandler; import kr.co.uplus.ez.common.data.ConfigProps; import kr.co.uplus.ez.common.jwt.JwtAuthCookieFilter; import kr.co.uplus.ez.common.jwt.JwtAuthHeaderFilter; import kr.co.uplus.ez.common.jwt.JwtExceptionFilter; import kr.co.uplus.ez.common.jwt.JwtProperties; import kr.co.uplus.ez.config.filter.VueStaticFilter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private static final String LOGIN_FORM_URL = "/login/**"; public static final String LOGIN_API_URL = "/api/v1/bo/login"; public static final String LOGIN_FAIL_URL = "/login?error=true"; public static final String LOGIN_SUCC_URL = "/"; private static final String API_URL = "/api/**"; public static final String TEST_PERMIT_URL = "/api/**/**"; public static final String PUBLIC_API_URL = "/api/v1/bo/**"; // 내부에서 인증없이 호출하는 API public static final String[] REST_API_URLS = {API_URL, TEST_PERMIT_URL}; private static final String[] PERMIT_URL_ARRAY = { "/login", "/api/v1/bo/login/**", "/v2/api-docs", "/swagger-resources", "/swagger-resources/**", "/configuration/ui", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/v3/api-docs/**", "/swagger-ui/**", "/" }; private static final String[] AUTH_URL_ARRAY = { "/api/v1/bo/login/*", "/api/v1/bo/comm/**", "/api/v1/bo/custMgt/**", "/api/v1/bo/sysMgt/**", "/api/v1/bo/channelMgt/**", "/api/v1/bo/sendNumMgt/**", "/api/v1/bo/mntrng/**", "/api/v1/bo/riskMgt/sendNum/**", "/api/v1/bo/stats/**" }; public static final String LOGIN_ID_PARAM = "userId"; @SuppressWarnings("unused") private static final String LOGIN_PWD_PARAM = "userPwd"; @Autowired private UserDetailsService userDetailsService; @Autowired private ConfigProps cprops; @Autowired private JwtProperties jwtProps; // @Autowired // private AuthService authService; @Override public void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/static/**", "/assets/**"); } @Bean public Filter jwtAuthFilter() { return new JwtAuthCookieFilter(jwtProps); } @Override public void configure(HttpSecurity http) throws Exception { http .addFilterBefore(new VueStaticFilter(), UsernamePasswordAuthenticationFilter.class) // Vue에서 호출시 화면관련 URL은 / forward // .addFilterBefore(new XssFilter(cprops), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtExceptionFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtAuthHeaderFilter(jwtProps), UsernamePasswordAuthenticationFilter.class); http .cors().and() .csrf().disable() // Spring Security가 HttpSession 객체를 생성하지 않도록 설정 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .headers().contentTypeOptions().disable() .and() .headers().frameOptions().disable() .and() .exceptionHandling() .authenticationEntryPoint(new MixedAuthenticationEntryPoint(LOGIN_FORM_URL, "/api/v1/bo/login/**")) .and() .authorizeRequests() .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() // CORS preflight 요청은 인증처리를 하지 않도록 설정 .antMatchers(PERMIT_URL_ARRAY).permitAll() .antMatchers(AUTH_URL_ARRAY).authenticated() .anyRequest().authenticated(); } @Override protected void configure(final AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public LoginSuccessHandler loginSuccessHandler() { return new LoginSuccessHandler(); } @Bean public LoginFailureHandler loginFailureHandler() { return new LoginFailureHandler(LOGIN_FAIL_URL); } }