Springboot

[Springboot] Filter와 Spring Security

KJihun 2023. 6. 30. 17:18
728x90

 

 

Spring에서 모든 호출은 DispatcherServlet을 통과하게 되고 이후에 각 요청을 담당하는 Controller로 분배된다.

이때, 각 요청에 대해서 공통적으로 처리해야 할 필요가 있을 때

DispatcherServlet 이전에 단계가 필요하며 이것이 Filter다.

 

SecurityFilterChain 상세구조

Spring Security도 인증 및 인가를 위해 Filter를 사용하며 FilterChainProxy를 통해서 상세로직을 구현한다

 

Spring security에서 제공하는 인증방식: Form login

Form Login 기반 인증: 인증이 필요한 URL 요청 시 인증되지 않았다면 로그인 페이지를 반환하는 구조

 

내부에서 인증을 처리할 때 가장 많이 사용되는 방식으로 usernamePasswordAuthenticationFilter가 있다.

 

usernamePasswordAuthenticationFilter 동작 방식


1. 클라이언트가 SecurityFilterChain으로 유저네임, 패스워드 전달

2. SecurityFilterChain가 usernamePasswordAuthenticationToken 생성
3.  AuthenticationManager에게 토큰 전달. 매니저는 인증을 시도함
4-1 성공 시: SecurityContextHolder에 usernamePasswordAuthenticationToken 저장
4-2 실패 시: SecurityContextHolder를 비운 후 loginpage로 redirect

SecurityContextHolder


- SecurityContext는 인증이 완료된 사용자의 상세 정보(Authentication)를 저장하는 공간이다
- SecurityContext는 SecurityContextHolder 로 접근할 수 있다.

예시코드

SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
context.setAuthentication(authentication); // SecurityContext 에 인증 객체 Authentication 를 저장

SecurityContextHolder.setContext(context);



- Authentication
    - 현재 인증된 사용자를 나타내며 SecurityContext에서 가져올 수 있다.
    - principal  :  사용자 식별
        - Username/Password 방식으로 인증할 때 일반적으로 UserDetails 인스턴스이다.

        - @AuthenticationPrincipal 을 사용하여 가져올 수 있다.
    - credentials : 주로 비밀번호, 대부분 사용자 인증에 사용한 후 비운다.
    - authorities : 사용자에게 부여한 권한을 GrantedAuthority로 추상화하여 사용한다.
    

    <UserDetails>
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        UserRoleEnum role = user.getRole();
        String authority = role.getAuthority();
    
        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(simpleGrantedAuthority);
    
        return authorities;
    }
    
    Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

 

 

 

 

기존 service 구조

 

security 사용 시 구조

security는 Controller가 실행되기 전 먼저 실행하기에 보안적인 측면과 속도 측면에서도 훨씬 좋다.

 

security 코드 예시

        // 로그인 사용
        http.formLogin((formLogin) ->
                formLogin
                        // 로그인 View 제공 (GET /api/user/login-page)
                        .loginPage("/api/user/login-page")
                        // 로그인 처리 (POST /api/user/login)
                        .loginProcessingUrl("/api/user/login")
                        // 로그인 처리 후 성공 시 URL
                        .defaultSuccessUrl("/")
                        // 로그인 처리 후 실패 시 URL
                        .failureUrl("/api/user/login-page?error")
                        .permitAll()
        );

 

 

예제코드 - security를 사용하지 않았을 때 인증 및 권한부여

 if ( ... ) {
            // 인증이 필요없는 기능들은 바로 요청 진행
            } else {
            // 나머지 요청은 인증 처리 진행
            // 토큰 확인
            String tokenValue = jwtUtil.getTokenFromRequest(httpServletRequest);
            if (StringUtils.hasText(tokenValue)) { // 토큰이 존재하면 검증 시작
                // JWT 토큰 substring
                // 토큰 검증
                // 토큰에서 사용자 정보 가져오기
                );
    // 다음 Filter 로 이동
            } else {
                throw new IllegalArgumentException("Not Found Token");
            }
        }
    }


security 사용 시 인증 및 권한부여

http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                        .requestMatchers("/api/user/**").permitAll()    //**: 전부라는 의미
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

 


Spring security 사용법


1. gradle의 dependencies 구현

    implementation 'org.springframework.boot:spring-boot-starter-security'


2. 사용할 클래스에 Spring Security 지원을 가능하게 하는 @EnableWebSecurity 작성
(세션방식으로 동작. 기본 default 로그인도 지원한다)



'Springboot' 카테고리의 다른 글

[Springboot] 관계 매핑(ORM; Object Relational Mapping) N:M  (0) 2023.07.07
[Springboot] Security  (0) 2023.07.01
[Springboot] login 구현  (0) 2023.06.29
[Springboot] @Valid  (0) 2023.06.28
[Springboot] PathVariable vs RequestParam  (0) 2023.06.23