프로그래밍/백엔드

Spring boot 3.2.x 버전에서 Spring Security 기본틀 구현

제로스크랩 2024. 4. 20. 19:20

최신 릴리즈 버전인 3.2.x로 스프링 시큐리티를 구현한 포스트가 너무 없다.

이 때문에 해당 프로젝트 초기에 심적부담이 매우 컸던 기억이 난다. 

 

우여곡절 끝에 프로젝트를 마무리했지만 스프링에 대한 지식의 흔들림이 느껴졌다.

이것이 '임포스터 증후군'의 시작 아닐까 싶다.

 

정상적으로 작동한다고 외면할 일이 아니라 스프링에 대한 전반적인 재학습이 필요함을 절실히 느낀다.

김영한 선생님 강의 충동구매 ㄱㄱ

 

java 17
spring boot 3.2.x

 

1. SecurityConfig

package com.org.mgt.common.config;

import jakarta.servlet.DispatcherType;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {

  private final LoginSuccessHandler loginSuccessHandler;
  private final LoginFailureHandler loginFailureHandler;
  private final UserDetailsService userDetailsService;

    @Bean
    public static BCryptPasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
   http.csrf(AbstractHttpConfigurer::disable)
     .authorizeHttpRequests(request -> request
       .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
       .requestMatchers(
         new AntPathRequestMatcher("/"),
         new AntPathRequestMatcher("/assets/**"),
         new AntPathRequestMatcher("/orp/board/popup/**"), //팝업노출
         new AntPathRequestMatcher("/login*"),
         new AntPathRequestMatcher("/error"),
         new AntPathRequestMatcher("/api*"),
         new AntPathRequestMatcher("/api-docs/**"),
         new AntPathRequestMatcher("/swagger-ui/**")
       ).permitAll()
       .anyRequest().authenticated()    // 어떠한 요청이라도 인증필요
     )
     .formLogin(login -> login    // form 방식 로그인 사용
       .loginPage("/login.do")    // [A] 커스텀 로그인 페이지 지정
       .loginProcessingUrl("/login-process")    // [B] submit 받을 url
       .usernameParameter("userId")    // [C] submit할 아이디
       .passwordParameter("pw")    // [D] submit할 비밀번호
       .permitAll()
       .successHandler(loginSuccessHandler)
       .failureHandler(loginFailureHandler)
     )
     .logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer
       .logoutSuccessUrl("/login.do")
       .logoutUrl("/logout")
       .deleteCookies("remember-me")
       .permitAll()
     ) // 로그아웃은 기본설정으로 (/logout으로 인증해제)
     .rememberMe(httpSecurityRememberMeConfigurer -> httpSecurityRememberMeConfigurer
       .rememberMeParameter("remember-me")
       .userDetailsService(userDetailsService)
       .alwaysRemember(false)
       .tokenValiditySeconds(3600)
     )
   ;

   return http.build();
    }
}

 

2. UserDetailsService

package com.org.mgt.common.config;

import com.org.mgt.common.vo.UserVO;
import com.org.mgt.system.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class CustomDetailService implements UserDetailsService{

    private final UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String userId) {
        UserVO userVo = new UserVO();
        userVo.setUserId(userId);
        UserVO member;
        UserDetails userDetails;

        try {
            member = userMapper.selectUserDetail(userVo);
            userDetails = User.builder()
                    .username(member.getUserId())
                    .password(member.getPw())
                    .roles(member.getRoles())
                    .build();

        } catch (NullPointerException e) {
            throw new UsernameNotFoundException("");
        }catch (Exception e) {
            throw new RuntimeException();
        }

        return userDetails;
    }
}
728x90
반응형