Web/Spring

[Spring] 스프링부트 + JPA + thymeleaf + Spring Security로 회원가입 + 게시판(수정, 삭제, 등록, 조회, 댓글, 좋아요) + 로그인 구현하기 #3 Spring Security 설정

poopooreum 2024. 8. 29. 19:57
반응형

✏️ WebSecurityConfig 클래스

@Configuration
@EnableWebSecurity(debug = true)
@RequiredArgsConstructor
public class WebSecurityConfig    {

    private final AuthenticationFilter authenticationFilter;

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                .requestMatchers("/", "/member/signup", "/member/login", "/signup", "/error","/image/**","/login","/css/**").permitAll()
                .requestMatchers("/member/comment/**").authenticated()
                .anyRequest().authenticated()
                );

        return http.build();
    }


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

 

SecurityFilterChain filterChain

  • 첫 화면, 로그인 화면, 회원가입 화면, 회원가입 url, 로그인 url는 모두 접근할 수 있도록 permitAll() 설정
  • 권한 불가로 에러가 떠도 화면을 보여줄 수 있도록, 이미지 출력시 오류가 뜨는 경우를 방지하기 위해 추가
  • 그 외 나머지 url은 모두 authentication을 설정해서 권한이 있는 사람만 접속할 수 있도록 설정
  • 스프링 시큐리티는 기본적으로 logout을 가지고 있기 때문에 disable시킴

PasswordEncoder

  • 비밀번호를 암호화 해주는 함수

✏️ AuthenticationFilter 클래스

@Component
@RequiredArgsConstructor
public class AuthenticationFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        HttpSession session = httpServletRequest.getSession();
        Optional<Object> userIdOptional = Optional.ofNullable(session.getAttribute("userId"));
        if (userIdOptional.isEmpty()) {
            SecurityContextHolder.getContext().setAuthentication(null);
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        Authentication authentication =
                new UsernamePasswordAuthenticationToken(userIdOptional.get().toString(), "", List.of());

        SecurityContextHolder.getContext().setAuthentication(authentication);

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}

스프링 시큐리티의 formlogin을 사용하지 않고 직접 form mehtod 방식을 구현하여 필자는 진행하였음

그래서 로그인 과정에서 authentication을 직접 설정해 주었는데 SecurityContextHolder의 특성상 한 번 요청을 처리하면 authentication을 날려버림 ⇒ 로그인 하고 첫 메인화면에서는 상관 없으나 댓글을 달거나 글을 쓰는 등의 작업을 하고 나서 메인화면으로 돌아오게 되면 인증이 풀려서 권한이 없는 상태로 바뀌어버림

그래서 직접 SecurityFilter를 구현

상속받을 수 있는 필터는 OncePerRequestFilter와 GenericFilterBean이 있으나 전자는 같은 서블릿 필터의 요청은 한 번만 수행하고 후자는 같은 서블릿 필터의 요청을 들어올 때마다 처리한다는 특성이 있음. 그래서 인증 처리는 요청시마다 한 번만 수행하면 된다고 생각했기 때문에 OncePerRequestFilter를 상속받음

필터 내용은 세션값을 가져오고 만약 세션값이 존재하지 않다면 SecurityContextHolder를 이용하여 인증 등록

더 자세한 건 여기를 클릭

반응형