JAVA

자바 스프링부트 2.7.7->3.3.9 업그레이드 (2)

생활개발 2025. 3. 5. 09:41
728x90

1편 바로가기 : 자바 스프링부트 2.7.7->3.3.9 업그레이드 (1)

 

1편에는 기본셋팅 gradle만 설정했었는데

이번엔 스프링시큐리티가 6버전으로 바뀌면서 오류 투성이!

기존)

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.session.HttpSessionEventPublisher;


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    DataSource dataSource;

    @Autowired
    SecurityDAO securitydao;

    @Autowired
    private LoginIdPwValidator userDetailService;

    @Value("${spring.config.activate.on-profile}")
    private String env;

    /* Session 관리 */
    @Bean
    SessionRegistry sessionRegistry() {
       return new SessionRegistryImpl();
    }

    /* SuccessHandler */
    @Bean
    LoginSuccessHandler loginSuccessHandler() { return new LoginSuccessHandler(); }

    /* FailureHandler */
    @Bean
    LoginFailureHandler loginFailureHandler() {    return new LoginFailureHandler(); }

    /* HttpSession 이벤트를 Spring 이벤트로 변환, 세션 생성 및 소멸 이벤트를 처리하는 데 도움이 된다. */
    @Bean
    public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
       return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
    }

    /* 아이디/비밀번호 exception 구분의 위함 */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
       DaoAuthenticationProvider bean = new DaoAuthenticationProvider();
       bean.setHideUserNotFoundExceptions(false); //기본으로 true로 지정, false 지정시 UsernameNotFoundException 사용 가능
       bean.setUserDetailsService(userDetailService);  //필수값
       bean.setPasswordEncoder(passwordEncoder());    //필수값
       return bean;
    }

    // 스프링시큐리티 표준 BCrypt 암호화 사용
    // 비밀번호 암호화 암호를 해제시키는 경우 BCryptPasswordEncoder를 사용한다.
    @Bean
    public PasswordEncoder passwordEncoder() {
       return new BCryptPasswordEncoder();
    }


    /*@Bean
    public PasswordEncoder getPasswordEncoder(){
       return new BCryptPasswordEncoder();
    }*/

    /*
     * 인증예외처리 : 스프링 시큐리티 룰을 무시하게 하는 URL 규칙
     * */
    @Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/img/**", "/vendor/**","/fonts/**");
		web.ignoring().antMatchers("/admin/find_idpw_proc", "/admin/find_idpw", "/admin/pw_mail", "/admin/reset_pw", "/admin/find_idpw_proc",
				"/admin/reset_pw_proc", "/admin/stat/chkVisitors_proc", "/admin/stat/chkUrlVisitors_proc");
	}

    /*
     * 설정 : 스프링 시큐리티 규칙
     * */
    @Override
    protected void configure(HttpSecurity http) throws Exception{
       http
          .csrf().disable()  //비활성. 적용시에는 POST, 토큰값 필수
          .antMatcher("/admin/**")   //뒤로갈수록 넓은 범위
             .authorizeRequests()   //요청에 의한 보안검사 시작
             // .antMatchers("/admin/newsletter_upload").authenticated() //로그인 해야 접속가능
             .antMatchers("/admin/**").authenticated() //admin 폴더 전부 로그인 해야 접속가능
                .anyRequest().authenticated() //MASTER, MAIN 권한만 접속 가능
       .and()
          .formLogin()   //보안 검증은 formLogin방식으로 하겠다.
          .loginPage("/admin/login")//사용자 정의 로그인 페이지
             .usernameParameter("username")//아이디 파라미터명 설정 : login Form에서 input 아이디 name이 username 이어야 인식 됨
             .passwordParameter("password")//패스워드 파라미터명 설정 : login Form에서 input 패스워드 name이 password 이어야 인식 됨
             .successHandler(loginSuccessHandler())
             .loginProcessingUrl("/admin/loginProc")//로그인 Form Action Url
             .permitAll() //로그인 페이지는 모두 접근 허용
             .failureHandler(loginFailureHandler())
       .and()
          .logout()
          .logoutUrl("/admin/logout") //로그아웃 url
          .logoutSuccessUrl("/admin/login")
          .invalidateHttpSession(true)
       .and()
          .sessionManagement()
             .maximumSessions(-1)
             .sessionRegistry(sessionRegistry())
       ;
    }
}

WebSecurityConfigurerAdapter가 5.7버전부터인가 없어졌다고함!

그래서 수정중..

configure 2개를 바꿔야하는데

먼저 HttpSecurity http 이부분부터!

변경전)

@Override
protected void configure(HttpSecurity http) throws Exception{
    http
       .csrf().disable()  //비활성. 적용시에는 POST, 토큰값 필수
       .antMatcher("/admin/**")   //뒤로갈수록 넓은 범위
          .authorizeRequests()   //요청에 의한 보안검사 시작
          // .antMatchers("/admin/newsletter_upload").authenticated() //로그인 해야 접속가능
          .antMatchers("/admin/**").authenticated() //admin 폴더 전부 로그인 해야 접속가능
               .anyRequest().authenticated() //MASTER, MAIN 권한만 접속 가능
    .and()
       .formLogin()   //보안 검증은 formLogin방식으로 하겠다.
       .loginPage("/admin/login")//사용자 정의 로그인 페이지
          .usernameParameter("username")//아이디 파라미터명 설정 : login Form에서 input 아이디 name이 username 이어야 인식 됨
          .passwordParameter("password")//패스워드 파라미터명 설정 : login Form에서 input 패스워드 name이 password 이어야 인식 됨
          .successHandler(loginSuccessHandler())
          .loginProcessingUrl("/admin/loginProc")//로그인 Form Action Url
          .permitAll() //로그인 페이지는 모두 접근 허용
          .failureHandler(loginFailureHandler())
    .and()
       .logout()
       .logoutUrl("/admin/logout") //로그아웃 url
       .logoutSuccessUrl("/admin/login")
       .invalidateHttpSession(true)
    .and()
       .sessionManagement()
          .maximumSessions(-1)
          .sessionRegistry(sessionRegistry())
    ;
}

 

변경후)

@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
       .csrf(csrf -> csrf.disable())  //비활성. 적용시에는 POST, 토큰값 필수
       //권한 설정
       .authorizeHttpRequests(request -> request //요청에 의한 보안검사 시작
          .requestMatchers("/admin/**").authenticated() //admin 폴더 전부 로그인 해야 접속가능
          .anyRequest().permitAll() // 그 외 모든 요청은 인증 없이 접근 가능
       )
       //로그인 설정
       .formLogin(login -> login //보안 검증은 formLogin방식으로 하겠다.
          .loginPage("/admin/login")//사용자 정의 로그인 페이지
          .loginProcessingUrl("/admin/loginProc")//로그인 Form Action Url
          .usernameParameter("username")//아이디 파라미터명 설정 : login Form에서 input 아이디 name이 username 이어야 인식 됨
          .passwordParameter("password")//패스워드 파라미터명 설정 : login Form에서 input 패스워드 name이 password 이어야 인식 됨
          .successHandler(loginSuccessHandler()) //로그인 성공 로직
          .failureHandler(loginFailureHandler()) //로그인 실패 로직
          .permitAll() //로그인 페이지는 모두 접근 허용
       )
       //로그아웃 설정
       .logout(logout -> logout
          .logoutUrl("/admin/logout") //로그아웃 url
          .logoutSuccessUrl("/admin/login") //로그아웃 성공 후 이동할 url
          .invalidateHttpSession(true) //세션 무효화 로그아웃 후 세션 모두 삭제
       )
       //세션 관리 설정
       .sessionManagement(session -> session //세션 관리 기능 활성화
          .maximumSessions(-1) //최대 허용 세선 수 -1이면 무제한
          .sessionRegistry(sessionRegistry()) //활성화 된 세션 정보를 관리
       )
    ;

    return http.build();
}

 

어노테이션부터 @Override -> @Bean으로 변경

상속받아오는 configure가 없어지면서 수정됨

csrf 비활성화)

//변경전
.csrf().disable()

//변경후
.csrf(csrf -> csrf.disable())

개인적으로 이거 찾는게 제일 힘들었음.

기존 .and()하는 체이닝 하는 방식에서 람다표현식으로 변경

그리고 스프링스큐리티 5->6으로 변경하면서 함수들도 많이 바뀌었음.

authorizeRequests() → authorizeHttpRequests() 

antMatchers(), antMatcher() -> requestMatchers()

이렇게 2개 함수가 바뀌어 수정

인증)

//변경전
.antMatcher("/admin/**")	//뒤로갈수록 넓은 범위
    .authorizeRequests()	//요청에 의한 보안검사 시작
    .antMatchers("/admin/**").authenticated() //admin 폴더 전부 로그인 해야 접속가능
    .anyRequest().authenticated() //MASTER, MAIN 권한만 접속 가능

//변경후
.authorizeHttpRequests(request -> request //요청에 의한 보안검사 시작
    .requestMatchers("/admin/**").authenticated() //admin 폴더 전부 로그인 해야 접속가능
    .anyRequest().permitAll() // 그 외 모든 요청은 인증 없이 접근 가능
)

 

그 외 로그인, 로그아웃, 세션관리 하는 부분은 다행히 크게 달리진 부분없이

표현식만 바뀌어서 수정!

로그인, 로그아웃, 세션)

//변경전
.and()
    .formLogin()	//보안 검증은 formLogin방식으로 하겠다.
    .loginPage("/admin/login")//사용자 정의 로그인 페이지
        .usernameParameter("username")//아이디 파라미터명 설정 : login Form에서 input 아이디 name이 username 이어야 인식 됨
        .passwordParameter("password")//패스워드 파라미터명 설정 : login Form에서 input 패스워드 name이 password 이어야 인식 됨
        .successHandler(loginSuccessHandler())
        .loginProcessingUrl("/admin/loginProc")//로그인 Form Action Url
        .permitAll() //로그인 페이지는 모두 접근 허용
        .failureHandler(loginFailureHandler())
.and()
    .logout()
    .logoutUrl("/admin/logout") //로그아웃 url
    .logoutSuccessUrl("/admin/login")
    .invalidateHttpSession(true)
.and()
    .sessionManagement()
        .maximumSessions(-1)
        .sessionRegistry(sessionRegistry())
        
//변경후
//로그인 설정
.formLogin(login -> login //보안 검증은 formLogin방식으로 하겠다.
    .loginPage("/admin/login")//사용자 정의 로그인 페이지
    .loginProcessingUrl("/admin/loginProc")//로그인 Form Action Url
    .usernameParameter("username")//아이디 파라미터명 설정 : login Form에서 input 아이디 name이 username 이어야 인식 됨
    .passwordParameter("password")//패스워드 파라미터명 설정 : login Form에서 input 패스워드 name이 password 이어야 인식 됨
    .successHandler(loginSuccessHandler()) //로그인 성공 로직
    .failureHandler(loginFailureHandler()) //로그인 실패 로직
    .permitAll() //로그인 페이지는 모두 접근 허용
)
//로그아웃 설정
.logout(logout -> logout
    .logoutUrl("/admin/logout") //로그아웃 url
    .logoutSuccessUrl("/admin/login") //로그아웃 성공 후 이동할 url
    .invalidateHttpSession(true) //세션 무효화 로그아웃 후 세션 모두 삭제
)
//세션 관리 설정
.sessionManagement(session -> session //세션 관리 기능 활성화
    .maximumSessions(-1) //최대 허용 세선 수 -1이면 무제한
    .sessionRegistry(sessionRegistry()) //활성화 된 세션 정보를 관리
)

 

이렇게보면 너~~~무 간단해 보이는데

이거 하는데만 1주일정도 걸렸다...

챗gpt쓰면서 하면 금방 하겠지~~ 했는데

얘도 잘 모르는거같았음

또 타임리프랑 컨트롤러쪽 수정하고 있는데 아마 3편에서 마무리할 것같습니다!

728x90