123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package com.its.op.security;
- import com.its.op.security.interceptor.UserLogoutHandler;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.HttpMethod;
- import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
- 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.session.SessionRegistry;
- import org.springframework.security.core.session.SessionRegistryImpl;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.web.session.HttpSessionEventPublisher;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- @Slf4j
- @Configuration
- @EnableWebSecurity
- @RequiredArgsConstructor
- //@EnableGlobalMethodSecurity(securedEnabled = true)
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- private final WebLoginService loginService;
- private final WebLoginSuccessHandler webLoginSuccessHandler;
- private final WebLoginFailureHandler webLoginFailureHandler;
- @Override
- public void configure(WebSecurity web) {
- web.ignoring().antMatchers("/favicon.ico");
- // static 디렉터리의 하위 파일 목록은 인증 무시 ( = 항상통과 )
- web.ignoring().antMatchers("/js/**", "/images/**", "/libs/**", "/css/**", "/application/fonts/**");
- //web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations()); // 정적 리소스 접근 가능하게
- web.ignoring().antMatchers(HttpMethod.GET, "/api/**"); // GET Method 는 모두 통과
- // cs-api
- web.ignoring().antMatchers(HttpMethod.GET, "/cs-api/**"); // GET Method 는 모두 통과
- web.ignoring().antMatchers(HttpMethod.POST, "/cs-api/**"); // GET Method 는 모두 통과
- web.ignoring().antMatchers(HttpMethod.PUT, "/cs-api/**"); // GET Method 는 모두 통과
- web.ignoring().antMatchers(HttpMethod.DELETE, "/cs-api/**"); // GET Method 는 모두 통과
- }
- @Override
- protected void configure(HttpSecurity http) {
- // URL 권한 설정
- //setAntMatchers(http, "ROLE_");
- try {
- http.csrf()
- .disable()
- ; // REST API 호출 유효하게(POST...)
- http
- .authorizeRequests()
- // SWAGGER 권한 설정
- .antMatchers("/swagger-ui.html", "/swagger/**", "/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll()
- // 웹소켓 권한 설정하지
- .antMatchers("/ws/**").permitAll()
- .antMatchers("/api/**").permitAll()
- // API 권한 설정하지
- //.antMatchers("/api/**").permitAll()
- // 지도 URI 권한 설정하지
- .antMatchers("/MAPDATA/**").permitAll()
- .antMatchers("/download/**").permitAll()
- // 페이지 권한 설정
- // .antMatchers("/application/facility/**", "/facility/**").permitAll()
- .antMatchers("/application/**", "/facility/**").permitAll()
- .antMatchers("/application/wall/**", "/wall/**").permitAll()
- .antMatchers("/application/login/**").permitAll()
- .antMatchers("/api/auth/**").permitAll()
- // .antMatchers("/api/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- // .loginPage("/application/login/login.html")
- .loginPage("/application/op/00.main/main.html")
- .loginProcessingUrl("/api/auth/login.do")
- .defaultSuccessUrl("/application/op/00.main/main.html", true)
- .usernameParameter("username")
- .passwordParameter("password")
- .successHandler(this.webLoginSuccessHandler)
- .failureHandler(this.webLoginFailureHandler)
- .permitAll()
- .and()
- .logout()
- //.logoutUrl("/api/auth/logout.do")
- //.logoutRequestMatcher(new AntPathRequestMatcher("/api/auth/logout.do"))
- .addLogoutHandler(new UserLogoutHandler()).permitAll()
- .logoutSuccessUrl("/application/login/login.html").permitAll()
- //.logoutSuccessUrl("/api/auth/login.do").permitAll()
- .invalidateHttpSession(true)
- .deleteCookies("JSESSIONID")
- .deleteCookies(WebMvcConfig.USER_UUID)
- .deleteCookies(WebMvcConfig.USER_TIME)
- .and()
- .sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 스프링 시큐리티가 필요 시 생성 (default)
- // 인증에 성공할 때 마다 세션 ID나 세션을 변경해서 발급해줌으로써
- // 세션을 중간에서 가로채더라도 해당 세션이 유효하지 않게 하는 기능
- .invalidSessionUrl("/application/login/login.html") // 세션이 유효하지 않을 경우 이동 할 페이지
- //.invalidSessionUrl("/api/auth/login.do") // 세션이 유효하지 않을 경우 이동 할 페이지
- .sessionFixation().changeSessionId() // changeSessionId : 새로운 세션 ID를 발급해서 전달(default)
- // none : 아무 동작 안함
- // migrateSession : 새로운 세션을 생성해서 전달 (속성값 유지)
- // newSession : 새로운 세션 전달 (속성값 유지 안됨)
- .maximumSessions(20) // 최대 허용 가능 세션 수, -1인 경우 무제한 세션 허용
- .maxSessionsPreventsLogin(true) // 동시 로그인 차단, false 인 경우 기존 세션 만료(default)
- .expiredUrl("/application/login/login.html") // 세션이 만료된 경우 이동 할 페이지
- //.expiredUrl("/api/auth/login.do") // 세션이 만료된 경우 이동 할 페이지
- .sessionRegistry(sessionRegistry())
- // .and()
- // .exceptionHandling()
- // .accessDeniedPage("/login.do")
- // .and()
- // .headers()
- // .defaultsDisabled()
- // .frameOptions()
- // .sameOrigin()
- // .cacheControl();
- // .and() // 로그아웃 설정
- // .logout()
- // .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
- // .logoutSuccessUrl("/login")
- // .invalidateHttpSession(true)
- // .deleteCookies("JSESSIONID")
- // .and()
- // // 403 예외처리 핸들링
- // .exceptionHandling().accessDeniedPage("/login");
- ;
- } catch (IOException e) {
- // FOR KISA Secure Coding pass
- log.error("{configure: IOException}");
- } catch (Exception e) {
- log.error("{configure: Exception}");
- }
- }
- public DaoAuthenticationProvider daoAuthenticationProvider() {
- DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
- authenticationProvider.setUserDetailsService(this.loginService);
- authenticationProvider.setPasswordEncoder(passwordEncoder());
- // loadUserByUsername 의 UsernameNotFoundException 이 BadCredentialsException 로 발생함.
- // Exception 을 catch 하기 위해서는 아래를 false 로 설정하면 됨.
- authenticationProvider.setHideUserNotFoundExceptions(true);
- return authenticationProvider;
- }
- @Override
- public void configure(AuthenticationManagerBuilder auth) {
- // loadUserByUsername 의 UsernameNotFoundException 를 처리하기 위해
- // AuthenticationProvider 를 빈으로 등록해서 사용자 로그인 처리를 수행한다.
- //auth.userDetailsService(this.loginService).passwordEncoder(passwordEncoder());
- auth.authenticationProvider(daoAuthenticationProvider());
- }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new WebPasswordEncoder();
- }
- @Bean
- public SessionRegistry sessionRegistry() {
- return new SessionRegistryImpl();
- }
- /**
- * 로그아웃을 했기 때문에 세션의 개수가 0이라 생각했는데 로그인이 안되었다.
- * 이에 대한 해결책으로 SessionRegistry 빈을 생성 후 sessionManagement 에 DI 시킨다.
- * @return
- */
- @Bean
- public static ServletListenerRegistrationBean httpSessionEventPublisher() {
- return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
- }
- protected List<Map<String, Object>> getAuthReq() {
- Map<String, Object> roll = new HashMap<>();
- // roll.put("id", "id");
- // roll.put("url", "url");
- // roll.put("hasAuthority", "auth");
- // roll.put("date", "date");
- return (List<Map<String, Object>>) roll;
- }
- protected void setAntMatchers(HttpSecurity http, String rolePrefix) {
- List<Map<String, Object>> list = getAuthReq();
- for(Map<String, Object> m : list) {
- // 쉼표(,)로 구분된 권한 정보를 분리 후 배열로 저장
- String[] roles = m.get("hasAuthority").toString().split(",");
- // 권한 앞에 접두사(rolePrefix) 붙임
- for(int ii = 0; ii < roles.length; ii++) {
- roles[ii] = rolePrefix + roles[ii].toUpperCase();
- }
- String url = m.get("url").toString();
- if(url.charAt(0) != '/') {
- url = "/" + url;
- }
- // url, 권한 정보를 넣는다.
- try {
- http.authorizeRequests()
- .antMatchers(url)
- .hasAnyAuthority(roles);
- } catch (IOException ie) {
- // FOR KISA Secure Coding pass
- log.error("setAntMatchers: IOException");
- } catch (Exception e) {
- log.error("setAntMatchers: Exception");
- }
- }
- try {
- http.authorizeRequests()
- .antMatchers("/**").permitAll()
- .anyRequest().authenticated();
- } catch (IOException ie) {
- // FOR KISA Secure Coding pass
- log.error("setAntMatchers: IOException, permitAll");
- } catch (Exception e) {
- log.error("setAntMatchers: Exception, permitAll");
- }
- }
- }
|