인프런 커뮤니티 질문&답변

msun0215님의 프로필 이미지
msun0215

작성한 질문수

스프링부트 시큐리티 & JWT 강의

JWTAuthorizationFilter에서,,

작성

·

467

0

강의를 토대로 로그인 페이지를 구현하고, 이를 이용해서 로그인 과정을 거치는 로직을 구현하는 도중에 문제가 발생했습니다.

커스텀 필터를 만들어서 각각 JWTAuthenticationFilter와 JWTAuthorizationFilter를 거치게끔 해놓고, JWTAuthenticationFilter까지는 잘 마무리 지었습니다만, successfulAuthentication 메소드에 response를 설정하고 JWTAuthorizationFilter로 넘길 때 request에 Token을 받아들이지 못합니다.(포스트맨으로 넘길 때는 잘 나오는데 왜그러는지 모르겠네요,,)

 

 

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        System.out.println("=========================================");
        System.out.println("Authentication이 실행됨 : 인증이 완료되었다는 뜻임");
        PrincipalDetails principalDetails=(PrincipalDetails)authResult.getPrincipal();



        //RSA방식이 아닌, Hash암호방식
        String jwtToken = JWT.create()
                .withSubject(principalDetails.getUsername())    // token 별명 느낌?
                        .withExpiresAt(new Date(System.currentTimeMillis()+JWTProperties.EXPIRATION_TIME))  // Token 만료 시간 -> 현재시간 + 만료시간
                                .withClaim("id", principalDetails.getMember().getMemberID())    // 비공개 Claim -> 넣고싶은거 아무거나 넣으면 됨
                                        .withClaim("username", principalDetails.getMember().getMemberName())    // 비공개 Claim
                                                .sign(Algorithm.HMAC512(JWTProperties.SECRET));  // HMAC512는 SECRET KEY를 필요로 함
        //String jwtToken =TokenUtils.generateJwtToken(principalDetails.getMember());
        response.addHeader(JWTProperties.HEADER_STRING, JWTProperties.TOKEN_PREFIX+jwtToken);
        response.setHeader(JWTProperties.HEADER_STRING, JWTProperties.TOKEN_PREFIX+jwtToken);
        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        System.out.println("response : "+response);
        System.out.println("JWTAuthenticationFilter에서의 response.getHeader('Authorization')) : "+response.getHeader(JWTProperties.HEADER_STRING));

 

[JWTAuthorizationFilter.java]


@Log4j2
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
    private final MemberRepository memberRepository;

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager, MemberRepository memberRepository){
        super(authenticationManager);
        System.out.println("JWTAuthorizationFilter : 인증이나 권한이 필요한 주소가 요청됨");
        System.out.println("=========================================");
        this.memberRepository=memberRepository;
    }


    // 인증이나 권한이 필요한 주소 요청이 있을 때 해당 필터를 타게 됨
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //String header=request.getHeader("Authorization");
        System.out.println("request : "+request);
        System.out.println("Authorization : "+request.getHeader(JWTProperties.HEADER_STRING));
        String header=request.getHeader(JWTProperties.HEADER_STRING);
        System.out.println("JWTAuthorizationFilter에서의 JWTHeader : "+header);  // JWT Token

//        Enumeration<String> headerNames = request.getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String headerName = headerNames.nextElement();
//            System.out.println("Header: " + headerName + ", Value: " + request.getHeader(headerName));
//        }


        // header가 있는지(유효한지) 확인
        // 토큰이 잘못될 경우 다음 filter로 흘려 보낸다.
        if(header==null||!header.startsWith(JWTProperties.TOKEN_PREFIX)){
            System.out.println("Not Allowed User");
            chain.doFilter(request,response);
            return;
        }

        // JWT Token을 검증해서 정상적인 사용자인지 확인
        String token = request.getHeader(JWTProperties.HEADER_STRING).replace(JWTProperties.TOKEN_PREFIX, "");
        String memberID = JWT.require(Algorithm.HMAC512(JWTProperties.SECRET)).build().verify(token).getClaim("memberID").asString();  // verify()를 통해서 서명
        System.out.println("token : "+token);
        System.out.println("memberID : "+memberID);
        // 서명이 정상적으로 동작했을 경우
        if(memberID!=null){
            Member memberEntity = memberRepository.findByMemberID(memberID);
            System.out.println("UserEntity 정상 : "  +memberEntity);
            PrincipalDetails principalDetails = new PrincipalDetails(memberEntity);
            System.out.println("MemberName : "+memberEntity.getMemberName());

            // JWT Token 서명을 통해서 서명이 정상적이면 Authentication 객체를 만들어준다.
            Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());
            System.out.println("JWTAuthorization에서의 authentication : "+authentication);
            // 강제로 Security의 Session에 접근하여서 Authentication 객체를 저장시킨다.
            SecurityContextHolder.getContext().setAuthentication(authentication);
            System.out.println("Successfully Saved Authentication" + authentication);

        }
        // super.doFilterInternal(request, response, chain);
        chain.doFilter(request,response);
    }
}

 

 

더 자세한 내용은 github 참고 부탁드립니다.

https://github.com/msun0215/SWProject/tree/1208

답변 2

0

최주호님의 프로필 이미지
최주호
지식공유자

SSR 프로젝트로 구현하신거죠? 템플릿 엔진을 쓰고 계신거죠?

그럼 mustache에서 Authorization에 값을 담아서 서버쪽으로 요청을 하려면, 자바스크립트로 요청해야 해요. 모든 요청이 자바스크립트 요청인가요?

msun0215님의 프로필 이미지
msun0215
질문자

우선은 테스트용으로 mustache와 연결된 html로만 구현해놓은 상태입니다

나중에 게시판과 통합할때 자바스크립트와 연결할 계획입니다

그럼 html에서는 서버에 요청할 수 없는 것인가요?

0

안녕하세요, 인프런 AI 인턴입니다.

질문 주신 JWTAuthorizationFilter에서 토큰을 받아들이지 못하는 문제와 관련하여, 다음과 같은 가능성들을 확인해보는 것이 좋을 것 같습니다.

  1. Response Header 확인: successfulAuthentication 메소드에서 응답 헤더에 토큰을 추가하는 방식을 확인합니다. 그리고 실제로 응답 헤더에 “Authorization”이라는 키에 올바르게 토큰이 설정되었는지 확인해보세요.

  2. Request Header 전달: 클라이언트에서 요청을 보낼 때, “Authorization” 헤더가 있고, 올바른 형식으로 토큰이 전달되고 있는지 확인합니다. 때때로 프론트엔드에서 헤더를 설정하는 부분에 오류가 있을 수 있으며, 이로 인해 서버 쪽에서 헤더를 제대로 받지 못할 수 있습니다.

  3. 토큰 형식: JWTProperties.TOKEN_PREFIX를 정확히 설정하셨는지, 그리고 토큰 앞에 제대로 붙어서 전달되고 있는지 확인하세요. 예를 들어, “Bearer “라는 접두어를 붙이는 것이 일반적입니다.

  4. 서버 로깅: 서버에서 인증 과정에 대한 로깅을 더 자세히 출력해서 요청과 응답의 헤더를 확인할 수 있도록 합니다. 문제가 발생하는 지점의 로그를 자세히 분석해보세요.

  5. 포스트맨 테스트와의 차이점: 포스트맨으로 테스트할 때와 실제 애플리케이션이 통신할 때의 차이를 분석해보세요. 특히 포스트맨에서는 기대한 대로 동작한다면, 클라이언트 측의 요청 구성에 주의를 기울여야 합니다.

  6. GitHub 코드 리뷰: GitHub에 올리신 코드를 다시 한번 자세히 리뷰해보세요. 세세한 부분에 오타나 논리적 오류가 없는지 확인하는 것도 중요합니다.

말씀하신 문제 해결을 위해서는 서버와 클라이언트 간의 통신 과정에서 보내는 헤더와 받는 헤더를 자세히 살펴보는 것이 중요합니다. 그리고, OAuth2, JWT와 같은 보안 관련 구현이 복잡할 수 있으므로, 문제가 발생한 부분을 하나씩 체계적으로 점검해나가야 합니다.

또한, Spring Security 관련하여 참고할 만한 공식 문서 링크를 아래에 첨부하니, 참고하시어 문제를 해결하시는 데 도움이 되었으면 좋겠습니다.

직접적인 문제 해결에 도움이 되시길 바랍니다.

msun0215님의 프로필 이미지
msun0215

작성한 질문수

질문하기