WebSecurityConfig.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package com.its.op.security;
  2. import com.its.op.security.interceptor.UserLogoutHandler;
  3. import lombok.RequiredArgsConstructor;
  4. import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.http.HttpMethod;
  8. import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
  9. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  10. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  11. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  12. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  13. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  14. import org.springframework.security.config.http.SessionCreationPolicy;
  15. import org.springframework.security.core.session.SessionRegistry;
  16. import org.springframework.security.core.session.SessionRegistryImpl;
  17. import org.springframework.security.crypto.password.PasswordEncoder;
  18. import org.springframework.security.web.session.HttpSessionEventPublisher;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. @Configuration
  23. @EnableWebSecurity
  24. @RequiredArgsConstructor
  25. //@EnableGlobalMethodSecurity(securedEnabled = true)
  26. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  27. private final WebLoginService loginService;
  28. private final WebLoginSuccessHandler webLoginSuccessHandler;
  29. private final WebLoginFailureHandler webLoginFailureHandler;
  30. @Override
  31. public void configure(WebSecurity web) {
  32. web.ignoring().antMatchers("/favicon.ico");
  33. // static 디렉터리의 하위 파일 목록은 인증 무시 ( = 항상통과 )
  34. web.ignoring().antMatchers("/js/**", "/images/**", "/libs/**", "/css/**", "/application/fonts/**");
  35. //web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations()); // 정적 리소스 접근 가능하게
  36. web.ignoring().antMatchers(HttpMethod.GET, "/api/**"); // GET Method 는 모두 통과
  37. // cs-api
  38. web.ignoring().antMatchers(HttpMethod.GET, "/cs-api/**"); // GET Method 는 모두 통과
  39. web.ignoring().antMatchers(HttpMethod.POST, "/cs-api/**"); // GET Method 는 모두 통과
  40. web.ignoring().antMatchers(HttpMethod.PUT, "/cs-api/**"); // GET Method 는 모두 통과
  41. web.ignoring().antMatchers(HttpMethod.DELETE, "/cs-api/**"); // GET Method 는 모두 통과
  42. }
  43. @Override
  44. protected void configure(HttpSecurity http) throws Exception {
  45. // URL 권한 설정
  46. //setAntMatchers(http, "ROLE_");
  47. http.csrf()
  48. .disable()
  49. ; // REST API 호출 유효하게(POST...)
  50. http
  51. .authorizeRequests()
  52. // SWAGGER 권한 설정
  53. .antMatchers("/swagger-ui.html", "/swagger/**", "/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll()
  54. // 웹소켓 권한 설정하지
  55. .antMatchers("/ws/**").permitAll()
  56. // API 권한 설정하지
  57. //.antMatchers("/api/**").permitAll()
  58. // 지도 URI 권한 설정하지
  59. .antMatchers("/MAPDATA/**").permitAll()
  60. .antMatchers("/download/**").permitAll()
  61. // 페이지 권한 설정
  62. .antMatchers("/application/facility/**", "/facility/**").permitAll()
  63. .antMatchers("/application/wall/**", "/wall/**").permitAll()
  64. .antMatchers("/application/login/**").permitAll()
  65. .antMatchers("/api/auth/**").permitAll()
  66. // .antMatchers("/api/**").permitAll()
  67. .anyRequest().authenticated()
  68. .and()
  69. .formLogin()
  70. .loginPage("/application/login/login.html")
  71. //.loginPage("/api/auth/login.do")
  72. .loginProcessingUrl("/api/auth/login.do")
  73. .defaultSuccessUrl("/application/op/00.main/main.html", true)
  74. .usernameParameter("username")
  75. .passwordParameter("password")
  76. .successHandler(this.webLoginSuccessHandler)
  77. .failureHandler(this.webLoginFailureHandler)
  78. .permitAll()
  79. .and()
  80. .logout()
  81. //.logoutUrl("/api/auth/logout.do")
  82. //.logoutRequestMatcher(new AntPathRequestMatcher("/api/auth/logout.do"))
  83. .addLogoutHandler(new UserLogoutHandler()).permitAll()
  84. .logoutSuccessUrl("/application/login/login.html").permitAll()
  85. //.logoutSuccessUrl("/api/auth/login.do").permitAll()
  86. .invalidateHttpSession(true)
  87. .deleteCookies("JSESSIONID")
  88. .deleteCookies(WebMvcConfig.USER_UUID)
  89. .deleteCookies(WebMvcConfig.USER_TIME)
  90. .and()
  91. .sessionManagement()
  92. .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 스프링 시큐리티가 필요 시 생성 (default)
  93. // 인증에 성공할 때 마다 세션 ID나 세션을 변경해서 발급해줌으로써
  94. // 세션을 중간에서 가로채더라도 해당 세션이 유효하지 않게 하는 기능
  95. .invalidSessionUrl("/application/login/login.html") // 세션이 유효하지 않을 경우 이동 할 페이지
  96. //.invalidSessionUrl("/api/auth/login.do") // 세션이 유효하지 않을 경우 이동 할 페이지
  97. .sessionFixation().changeSessionId() // changeSessionId : 새로운 세션 ID를 발급해서 전달(default)
  98. // none : 아무 동작 안함
  99. // migrateSession : 새로운 세션을 생성해서 전달 (속성값 유지)
  100. // newSession : 새로운 세션 전달 (속성값 유지 안됨)
  101. .maximumSessions(20) // 최대 허용 가능 세션 수, -1인 경우 무제한 세션 허용
  102. .maxSessionsPreventsLogin(true) // 동시 로그인 차단, false 인 경우 기존 세션 만료(default)
  103. .expiredUrl("/application/login/login.html") // 세션이 만료된 경우 이동 할 페이지
  104. //.expiredUrl("/api/auth/login.do") // 세션이 만료된 경우 이동 할 페이지
  105. .sessionRegistry(sessionRegistry())
  106. // .and()
  107. // .exceptionHandling()
  108. // .accessDeniedPage("/login.do")
  109. // .and()
  110. // .headers()
  111. // .defaultsDisabled()
  112. // .frameOptions()
  113. // .sameOrigin()
  114. // .cacheControl();
  115. // .and() // 로그아웃 설정
  116. // .logout()
  117. // .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
  118. // .logoutSuccessUrl("/login")
  119. // .invalidateHttpSession(true)
  120. // .deleteCookies("JSESSIONID")
  121. // .and()
  122. // // 403 예외처리 핸들링
  123. // .exceptionHandling().accessDeniedPage("/login");
  124. ;
  125. }
  126. public DaoAuthenticationProvider daoAuthenticationProvider() {
  127. DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
  128. authenticationProvider.setUserDetailsService(this.loginService);
  129. authenticationProvider.setPasswordEncoder(passwordEncoder());
  130. // loadUserByUsername 의 UsernameNotFoundException 이 BadCredentialsException 로 발생함.
  131. // Exception 을 catch 하기 위해서는 아래를 false 로 설정하면 됨.
  132. authenticationProvider.setHideUserNotFoundExceptions(true);
  133. return authenticationProvider;
  134. }
  135. @Override
  136. public void configure(AuthenticationManagerBuilder auth) throws Exception {
  137. // loadUserByUsername 의 UsernameNotFoundException 를 처리하기 위해
  138. // AuthenticationProvider 를 빈으로 등록해서 사용자 로그인 처리를 수행한다.
  139. //auth.userDetailsService(this.loginService).passwordEncoder(passwordEncoder());
  140. auth.authenticationProvider(daoAuthenticationProvider());
  141. }
  142. @Bean
  143. public PasswordEncoder passwordEncoder() {
  144. return new WebPasswordEncoder();
  145. }
  146. @Bean
  147. public SessionRegistry sessionRegistry() {
  148. return new SessionRegistryImpl();
  149. }
  150. /**
  151. * 로그아웃을 했기 때문에 세션의 개수가 0이라 생각했는데 로그인이 안되었다.
  152. * 이에 대한 해결책으로 SessionRegistry 빈을 생성 후 sessionManagement 에 DI 시킨다.
  153. * @return
  154. */
  155. @Bean
  156. public static ServletListenerRegistrationBean httpSessionEventPublisher() {
  157. return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
  158. }
  159. protected List<Map<String, Object>> getAuthReq() {
  160. Map<String, Object> roll = new HashMap<>();
  161. // roll.put("id", "id");
  162. // roll.put("url", "url");
  163. // roll.put("hasAuthority", "auth");
  164. // roll.put("date", "date");
  165. return (List<Map<String, Object>>) roll;
  166. }
  167. protected void setAntMatchers(HttpSecurity http, String rolePrefix) throws Exception {
  168. List<Map<String, Object>> list = getAuthReq();
  169. System.out.println(list);
  170. for(Map<String, Object> m : list) {
  171. // 쉼표(,)로 구분된 권한 정보를 분리 후 배열로 저장
  172. String[] roles = m.get("hasAuthority").toString().split(",");
  173. // 권한 앞에 접두사(rolePrefix) 붙임
  174. for(int ii = 0; ii < roles.length; ii++) {
  175. roles[ii] = rolePrefix + roles[ii].toUpperCase();
  176. }
  177. String url = m.get("url").toString();
  178. if(url.charAt(0) != '/') {
  179. url = "/" + url;
  180. }
  181. // url, 권한 정보를 넣는다.
  182. http.authorizeRequests()
  183. .antMatchers(url)
  184. .hasAnyAuthority(roles);
  185. }
  186. http.authorizeRequests()
  187. .antMatchers("/**").permitAll()
  188. .anyRequest().authenticated();
  189. }
  190. }