본문 바로가기
개발/Security

[SpringBoot] Security + JWT(Access , Refresh) - JwtAuthenticationFilter

by 코딩하는 흰둥이 2024. 9. 25.

이전글

https://greed-yb.tistory.com/289

 

[SpringBoot] Security + JWT(Access , Refresh) - JwtTokenUtil

이전글https://greed-yb.tistory.com/288 [SpringBoot] Security + JWT(Access , Refresh) - SecurityConfig권한에 따른 인증/인가 방식은 이전글을 참고하길 바란다https://greed-yb.tistory.com/223 [SpringBoot] Security 로그인 인증,

greed-yb.tistory.com

 

 

 

filter.class
import com.example.practice.security.jwt.JwtTokenUtil;
import com.example.practice.service.user.UserService;
import com.example.practice.vo.UserVo;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    // 권한 정보를 가져오기 위한 코드, 페이지 체크 시 필요하면 본인 환경에 맞게 구현할것
    private UserService userService;

    private final JwtTokenUtil jwtTokenUtil;

    public JwtAuthenticationFilter(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        String aToken = getJwtFromRequest(request);          // Access Token 가져오기
        String rToken = getRefreshTokenFromRequest(request); // Refresh Token 가져오기

        // 유효한 access token 인 경우
        if (aToken != null && jwtTokenUtil.validateAccessToken(aToken)) {
            String username = jwtTokenUtil.getUsernameFromAccessToken(aToken);

            // 권한 정보 가져오기
            UserVo vo = userService.getUserById(username);
            List<GrantedAuthority> role = getAuthoritiesFromRoles(vo);

            // 인증 정보 생성
            // 1. 권한 정보 없을때
//            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, vo.getPassword(), new ArrayList<>());

            // 2. 권한 정보 있을때
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, vo.getPassword(), role );

            // 사용자 정보 set
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
        }
        // access token 이 만료되었고 refresh token 은 유효한 경우
        else if(aToken == null && jwtTokenUtil.validateRefreshToken(rToken)) {

            // refresh token 정보를 가져와서 새로운 access token 발급
            if (rToken != null) {
                String username = jwtTokenUtil.getUsernameFromRefreshToken(rToken);
                String newAccess = jwtTokenUtil.generateAccessToken(username);

                // 새로운 access token 로 변경
                response.setHeader("Authorization", "Bearer " + newAccess);

                Cookie accessTokenCookie = new Cookie("accessToken", newAccess);
                accessTokenCookie.setHttpOnly(true);
                accessTokenCookie.setPath("/");
                accessTokenCookie.setMaxAge(60 * 60);
                response.addCookie(accessTokenCookie);


                // 인증 정보 생성
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());

                // 사용자 정보 set
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }else{
            // token 이 존재하지 않으면
            chain.doFilter(request, response);
            return;
        }

        chain.doFilter(request, response);
    }


    // 사용자의 권한 가져와서 반환
    private List<GrantedAuthority> getAuthoritiesFromRoles(UserVo vo) {
        List<GrantedAuthority> role = new ArrayList<>();

        // 한 계정에 여러개의 권한을 가지고 있으면 List 로 받아와서 넣어줄 것
        role.add(new SimpleGrantedAuthority(vo.getRole()));

        return role;
    }


    // 쿠키에서 Access Token 가져오기
    private String getJwtFromRequest(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("accessToken".equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

    // 쿠키에서 Refresh Token 가져오기
    public String getRefreshTokenFromRequest(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("refreshToken")) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}

댓글