[백엔드] 도전! 실전 인증인가

2026. 5. 27. 17:51·CS/백엔드

아

 

https://dev-dx2d2y-log.tistory.com/218

 

[백엔드] 로그인 시의 SecurityFilterChain의 동작과정

https://dev-dx2d2y-log.tistory.com/217 [백엔드] Spring Security 첫 걸음 - DelegatingFilterProxy, FilterChainProxy로 Web Context Filter에 Spring Bean Filter 등DelegatingFilterProxy그 전에 그냥 HTTP 요청이 어떻게 처리되냐면..클라

dev-dx2d2y-log.tistory.com

이번 겨울에 스프링 시큐리티를 공부하면서 몇 가지 연습개발도 해보고 개념도 익혔는데, 이걸 실제로 적용시켜보려니까 약간 막히는 부분이 있어서 최종적으로 정리를 하고 넘어가려한다. 레디스로 배워왔고, 기존에 구식으로 남아있던 JWT토큰 관련 지식들도 업데이트할 요령으로 글을 써본다.


로그인 / 로그아웃

https://dev-dx2d2y-log.tistory.com/218

 

[백엔드] 로그인 시의 SecurityFilterChain의 동작과정

https://dev-dx2d2y-log.tistory.com/217 [백엔드] Spring Security 첫 걸음 - DelegatingFilterProxy, FilterChainProxy로 Web Context Filter에 Spring Bean Filter 등DelegatingFilterProxy그 전에 그냥 HTTP 요청이 어떻게 처리되냐면..클라

dev-dx2d2y-log.tistory.com

원래는 스프링 기본 폼로그인을 사용한다면 UsernamePasswordAuthenticationFilter를 사용해도되지만, 사실 로그인 과정이라는 것이 레포지토리라던가, 아니면 다른 서비스계층이라던가하는, 필터 로직보다는 비즈니스 로직에 더 밀접하게 연관되어있다. 따라서 커스텀 로그인을 진행하려면 필터단에서 진행하는 것보다는 비즈니스 로직에서 진행하는 것이 더 좋다고.

 

이외에는 별거없다. 토큰을 발급하고, 저장하고.. 이런 용도

로그아웃도 마찬가지. 비즈니스 로직으로 로그아웃 요청을 받아서 레디스의 내용만 지우면 된다.


레디스를 통한 RTR

JWT토큰에 대해서도 내용을 덧붙여보자면, accessToken을 발급하고 refreshToken도 발급하는 등 기본 플로우는 바뀔게 없지만 refreshToken을 가지고 accessToken을 재발급하는 과정을 다뤄보자면..

 

0. 서버는 accessToken과 refreshToken을 발급하고, accessToken은 쿠키 또는 프론트엔드 메모리에, refreshToken은 쿠키와 레디스에 저장한다.

1. accessToken을 발급받고 서비스를 이용하던 사용자의 accessToken이 만료된다.

2. accessToken이 만료되면 서버는 401 에러를 반환한다.

3. 401 에러가 반환되면 클라이언트는 accessToken 재발급 요청을 보내게되고, 서버는 이 요청을 받아서 쿠키의 refreshToken을 확인 및 redis에 저장된 값과 비교한다.

4-1. 값이 일치하지 않으면 토큰이 탈취된 것으로 간주하고 토큰을 전부 제거한다.

4-2. 값이 일치하면 새 토큰을 발급하고, 기존토큰은 제거한다.

 

뭐 이런 형식으로 이어진다..

@Transactional(readOnly = true)
    public TokenReissueResponseDTO reIssueToken(String refreshToken){
        String email = tokenProvider.getEmailFromToken(refreshToken);

        String refreshTokenInRedis = redisTemplate.opsForValue().get(
                "refreshToken:" + email
        );

        if (refreshTokenInRedis == null){
            throw new CustomException(ErrorCode.REFRESH_TOKEN_NOT_FOUND);
        }

        if (!refreshToken.equals(refreshTokenInRedis)){
            redisTemplate.delete("refreshToken:"+email);
            throw new CustomException(ErrorCode.REFRESH_TOKEN_REUSED);
        }

        User user = userFinder.findByEmail(email);

        UserDetails userDetails = CustomUserDetails.of(user);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
        );

        String accessToken = tokenProvider.createToken(email, authentication, JWTType.ACCESS);
        String newRefreshToken = tokenProvider.createToken(email, authentication, JWTType.REFRESH);

        redisTemplate.opsForValue().set(
                "refreshToken:" + user.getEmail(),
                newRefreshToken,
                JWTType.REFRESH.getValidTime(),
                TimeUnit.SECONDS
        );

        return new TokenReissueResponseDTO(accessToken, newRefreshToken);
    }

예전에는 토큰을 DB에서 관리했기 때문에 TTL 설정이 다소 복잡한 감이 있었는데 레디스를 사용함으로써 TTL 관리가 더 쉬워짐에 따라 더 깔끔한 RTR이 가능해졌다. accessToken은 인메모리 또는 쿠키에, refreshToken은 쿠키와 레디스에 저장해 RTR 때마다 검증하는 방법으로 갈 수 있겠다. 쿠키에 저장할 때에는 Secure, HttpOnly, SameSite 설정을 사용해 보안취약점을 방지해야한다.

 

사실 새로 배운 내용은 없긴한데.. 레디스를 처음 써보기도했고, 지디지 플젝트랙 이후로 RTR도 오랜만에 구현해보는거라 적어보았다.


인증필터

https://dev-dx2d2y-log.tistory.com/219

 

[골든리포트!] 7) JWT토큰 인증과정을 Spring Security 필터체인에 태워보기

저번에 인증과정에서 SecurityFilterChain을 어느정도 알아보았다. 이번에는 저번에 만들어본 JWTAuthorizationFilter를 수정해보도록한다. https://dev-dx2d2y-log.tistory.com/216 [골든리포트!] 6) 필터체인에서 JWT필

dev-dx2d2y-log.tistory.com

예전에 스프링 시큐리티를 배울 때에는 AuthenticationFilter, AuthenticationManager, AuthenticationProvider 등등 다양한 객체들이 인증과정에 참여했지만, JWT토큰을 사용하면 STATELESS하기도하고, 생각보다 관리할 것도 적어서 그냥 AuthenticationFilter만 적용시키면 된다.

 

사실 필터 내용도 별 다른 차이점은 크게 없는데, 그냥 책임을 조금 조정한 것이다. 요청에서 토큰을 가져오는 것과, 토큰의 식별자를 통해 Authentication 객체를 만드는 것을 기존에는 필터의 책임이었다면 JWT토큰을 관리하는 객체의 책임으로 넘어갔다 정도?

 

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain filterChain) throws ServletException, IOException {
        try {

            String accessToken = tokenProvider.getTokenFromHeader(req);

            if (!StringUtils.hasText(accessToken)) {
                filterChain.doFilter(req, res);
                return;
            }

            Authentication authentication = tokenProvider.getAuthentication(accessToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(req, res);

        } catch (CustomException ce){
            ce.printStackTrace();
            throw new CustomAuthenticationException(ce);
        }
    }

그래서 인증필터의 로직도 깔끔해졌다.

tokenProvider 객체가 요청에서 토큰 가져오기, Authentcation 객체 생성하기 등의 책임을 담당하게 되었다. 다만 그런만큼 tokenProvider 객체의 책임이 좀 늘어났는데, 그 책임이 원래 tokenProvider의 책임이기도하고ㅇㅇ..


암튼 그래서

 

1. 로그인/로그아웃은 필터단 말고 서비스단에서 처리하자

2. 레디스를 통해 더 간편한 RTR이 가능해졌다.

정도가 되겠다.

 

스프링 시큐리티.. 배울 때 정말 재밌게 배웠는데 오래 안쓰니까 까먹기도하고, 이걸 내 개인프로젝트가 아니라 실전 개발에 적용시켜본 것도 처음이기도하고, 암튼 그렇다. 세오스 스터디에서도 배웠는데 몇 개 또 까먹은 것 같기도하고.. 그리고 사실 스프링 시큐리티를 처음 배울 때 했던 프로젝트는 폼 로그인 없이 그냥 OAuth2에게 로그인을 맡겼던 것이기 때문에.. 뭔가 좀 다르기도했다.

 

그래도 스프링 시큐리티에 대해서는 확실하게 더 배울 수 있었다. 잘 쓰이진 않지만 AuthenticationFilter 이후의 필터들 (AnonymousAuthenticatilFilter, RememberMeAuthenticationFilter 등...)에 대한 지식도 조금 가지고 있으니, 이것들과 섞으면 또 다른 동아리나, 스터디를 진행할 때 하나의 장점으로 세울 수 있을 것 같다.

 

기초적인 로그인 및 인증인가기능은 그래도 좀 터득했다고 할 수 있으려나. 작년에 처음 로그인 로직 다루고 거의 1년 만에 여기까지 왔는데, 확실히 어렵다. 지디지 플젝트랙 때 코멤 분께서 로그인 어렵다고 경고 아닌 경고를하셨는데, 그 말이 맞습니다..

'CS > 백엔드' 카테고리의 다른 글

[백엔드] 락을 통해 동시성 해결하기 - 모니터락, DB락, 분산락(레디스)  (0) 2026.04.21
[백엔드] 스프링 컴포넌트 스캔과 Bean 등록하기 및 DI  (0) 2026.03.16
[백엔드] 인증요청 시의 SecurityFilterChain의 동작과정  (0) 2026.02.18
[백엔드] 로그인 시의 SecurityFilterChain의 동작과정  (0) 2026.02.16
[백엔드] Spring Security 첫 걸음 - DelegatingFilterProxy, FilterChainProxy로 Web Context Filter에 Spring Bean Filter 등록하기  (0) 2026.02.14
'CS/백엔드' 카테고리의 다른 글
  • [백엔드] 락을 통해 동시성 해결하기 - 모니터락, DB락, 분산락(레디스)
  • [백엔드] 스프링 컴포넌트 스캔과 Bean 등록하기 및 DI
  • [백엔드] 인증요청 시의 SecurityFilterChain의 동작과정
  • [백엔드] 로그인 시의 SecurityFilterChain의 동작과정
컬러잇
컬러잇
탄천러너지망생
  • 컬러잇
    Color it
    컬러잇
  • 전체
    오늘
    어제
    • 분류 전체보기 (235) N
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (72) N
        • JVM (12)
        • 인프라 (5)
        • 백엔드 (22) N
        • 논리회로 (5)
        • 언어구현 (1)
        • 인공지능 (1)
        • 코드설계 (3)
        • 컴퓨터구조 (9)
        • 데이터베이스 (4)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (65)
        • Java | Kotlin (49)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (4)
      • 고찰 (35)
        • CEOS 23기 회고록 (9)
  • 링크

    • 교양있는컬러잇
  • 최근 글

  • 인기 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.5
컬러잇
[백엔드] 도전! 실전 인증인가
상단으로

티스토리툴바