나와바리 - Spring Security + JWT를 이용한 로그인 API 구현(3)

Sungmin·2023년 5월 12일
0

JwtAuthenticationProcessingFilter 코드 설명

필터진행

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().startsWith(NO_CHECK_URL)) {
            filterChain.doFilter(request, response);
            return;
        }

        String refreshToken = jwtService.extractRefreshToken(request)
                .filter(jwtService::isTokenValid)
                .orElse(null);

        if (refreshToken != null) {
            checkRefreshTokenAndReIssueAccessToken(response, refreshToken);
            return;
        }
        
        if (refreshToken == null) {
            checkAccessTokenAndAuthentication(request, response, filterChain);
        }
    }

먼저 NO_CHECK_URL에 필터를 거치지않을 url을 설정해야한다.
설정한 URL이 들어올 경우 filterChain.doFilter(request, response);로 다음필터를 호출한다. return해 주는이유는 밑으로 내려가 진행되기 때문.

사용자 요청 헤더에서 RefreshToken을 추출하고 없거나 유효하지않으면 null반환.

RefreshToken이 존재한다면 DB의 RefreshToken과 일치하는지 확인 후 AccessToken을 재 발급해 준다.

RefreshToken이 존재하지않을경우, AccessToken을 검사하고 인증처리 로직 수행.
AccessToken이 없거나 유효하지 않다면 403에러발생하고
유효하다면 인증 객체가 담긴 상태로 다음 필터로 넘어가기 때문에 인증 성공.


    public void checkRefreshTokenAndReIssueAccessToken(HttpServletResponse response, String refreshToken) {
        memberRepository.findByRefreshToken(refreshToken)
                .ifPresent(member -> {
                    String reIssuedRefreshToken = reIssueRefreshToken(member);
                    jwtService.sendAccessAndRefreshToken(response, jwtService.createAccessToken(member.getEmail()),
                            reIssuedRefreshToken);
                });
    }
    

파라미터로 들어온 헤더에서 refreshToken으로 DB에서 회원을 찾고, 존재하면 AccessToken을 생성하고 reIssueRefreshToken()메서드로 리프레시 토큰
재발급 & 업데이트.


RefreshToken 재발급 & 업데이트

    private String reIssueRefreshToken(Member member) {
        String reIssuedRefreshToken = jwtService.createRefreshToken();
        member.updateRefreshToken(reIssuedRefreshToken);
        memberRepository.saveAndFlush(member);
        return reIssuedRefreshToken;
    }

AccessToken 체크 & 인증처리 메서드

    public void checkAccessTokenAndAuthentication(HttpServletRequest request, HttpServletResponse response,
                                                  FilterChain filterChain) throws ServletException, IOException {
        log.info("checkAccessTokenAndAuthentication() 호출");
        jwtService.extractAccessToken(request)
                .filter(jwtService::isTokenValid)
                .ifPresent(accessToken -> jwtService.extractEmail(accessToken)
                        .ifPresent(email -> memberRepository.findByEmail(email)
                                .ifPresent(this::saveAuthentication)));

        filterChain.doFilter(request, response);
    }
  • request에서 AccessToken을 추출한 후, 유효성검사를 진행.
  • 유효하면, Email을 추출하여 유저를 찾음.
  • 그 유저를 saveAuthentication()으로 인증 처리.
  • 인증 허가 처리된 객체를 SecurityContextHolder에 담기
  • 그 후 다음 인증 필터로 진행

인증 허가 메서드

    public void saveAuthentication(Member myMember) {
        String password = myMember.getPassword();
        if (password == null) {
            password = PasswordUtil.generateRandomPassword();
        }

        UserDetails userDetailsUser = org.springframework.security.core.userdetails.User.builder()
                .username(myMember.getEmail())
                .password(password)
                .roles(myMember.getRole().name())
                .build();

        Authentication authentication =
                new UsernamePasswordAuthenticationToken(userDetailsUser, null,
                        authoritiesMapper.mapAuthorities(userDetailsUser.getAuthorities()));

        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
  • 비밀번호 임의 설정하여 인증되도록 함.
  • 빌더의 유저 : UserDetailsUser 객체
  • credential(보통 비밀번호로, 인증 시에는 보통 null로 제거)
profile
Let's Coding

0개의 댓글