강의

멘토링

커뮤니티

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

tobot222님의 프로필 이미지
tobot222

작성한 질문수

코드로 배우는 React 19 with 스프링부트 API서버

JWT와 @PreAuthorize 사용하기에서 권한오류

작성

·

132

0

동영상 강의에 있는 내용대로 ProductController에서 @GetMapping("/list")에 @PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')")를 작성하고나서 postman에 login 후 accessToken을 가져와서 get방식으로 토큰을 넣어서 입력하면 status : 500, "error": Interner Server Error가 뜹니다.. @PreAuthorize부분을 주석처리하고 실행해보면 list값이 잘 나오네요.. 어디부분이 잘못 된걸까요??

참고로 CustomSecurityConfig클래스에 @EnableMethodSecurity추가도 했습니다.

@PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')")
@GetMapping("/list")
public PageResponseDTO<ProductDTO> list(PageRequestDTO pageRequestDTO){
    return productService.getList(pageRequestDTO);
}

여기가 ProductController 클래스

package org.zerock.apiserver.security.filter;

import com.google.gson.Gson;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import org.zerock.apiserver.dto.MemberDTO;
import org.zerock.apiserver.util.JWTUtil;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;


@Log4j2
public class JWTCheckFilter extends OncePerRequestFilter {


    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        //true == not check

        String path = request.getRequestURI();

        log.info("------check uri---------"+path);

        if(path.startsWith("/api/member/")){
            return true;
        }


        //false == check
        return false;
    }

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

        log.info("----------------------");
        log.info("----------------------");
        log.info("----------------------");


        String autoHeaderStr = request.getHeader("Authorization");

        //bearer // 7개 후 JWT 문자열
        try {
            String accessToken = autoHeaderStr.substring(7);
            Map<String, Object> claims = JWTUtil.validateToken(accessToken);
            log.info("JWT claims: " + claims);

//            filterChain.doFilter(request, response);
            String email = (String) claims.get("email");
            String pw = (String) claims.get("pw");
            String nickname = (String) claims.get("nickname");
            Boolean social = (Boolean) claims.get("social");
            List<String> roleNames = (List<String>) claims.get("roleNames");

            MemberDTO memberDTO = new MemberDTO(email, pw, nickname, social.booleanValue(), roleNames);

            log.info("---------------------------------");
            log.info(memberDTO);
            log.info(memberDTO.getAuthorities());

            UsernamePasswordAuthenticationToken authenticationToken
                    = new UsernamePasswordAuthenticationToken(memberDTO, pw, memberDTO.getAuthorities());

            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            filterChain.doFilter(request, response);

        }catch(Exception e){
            log.error("JWT Check Error --------------------");
            log.error(e.getMessage());

            Gson gson = new Gson();
            String msg = gson.toJson(Map.of("error", "ERROR_ACCESS_TOKEN"));

            response.setContentType("application/json");
            PrintWriter printWriter = response.getWriter();
            printWriter.println(msg);
            printWriter.close();


        }




        //destination
        filterChain.doFilter(request, response);

    }
}
여기가 JWTCheckFilter부분입니다.

답변 2

1

구멍가게코딩단님의 프로필 이미지
구멍가게코딩단
지식공유자

음.. 500 에러라면 서버 내부 에러라는 얘기네요.

@PreAuthorize를 붙인 이후 에러가 나셨다고 하셨네요..

 

우선은 Postman 등에서 JWT 전송이 제대로 되었는지 확인하는게 필요합니다.

 

서버 쪽에서는

  • JWTFilter에서 예외가 발생하지 않는지 확인하시고

@EnableMethodSecurity(prePostEnabled = true)

설정이 필요한데 있는지 확인해 보셔야 할 듯 합니다.

강의와 동일한 예제로 작성하셨다면 백엔드 코드를 cookie_00@naver.com로 알려주시면 테스트해 볼 수 있습니다.

 

 

 

 

 

 

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

섹션7번 처음부터 다시 들어보니, MemberDTO에서 ""ROLE+str이 되어야 하는데, "Role"+str로 타이핑이 되어있었습니다... 그래도 답변해주셔서 감사합니다!

0

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

@PreAuthorize와 연관된 문제는 보통 사용자 인증 및 권한 설정과 관련된 부분에서 발생할 수 있습니다. 설명해주신 상황으로 봤을 때, 사용자의 역할이나 권한 정보가 제대로 설정되지 않아서 발생하는 문제일 가능성이 높습니다. 몇 가지 점검 사항과 해결 방법을 제안드립니다.

1. JWTCheckFilter에서의 문제

  1. JWT Claims 확인: JWTUtil.validateToken(accessToken)에서 반환되는 claims 맵에 사용자의 역할(roleNames) 정보가 제대로 포함되어 있는지 확인이 필요합니다.

    • claims 맵에 roleNames가 리스트 형식으로 포함되어 있어야 @PreAuthorize 어노테이션이 작동할 수 있습니다. roleNames 리스트에 사용자의 권한이 제대로 셋업되어 있는지 로그를 찍어 확인해보세요.
  2. Authentication 설정: UsernamePasswordAuthenticationToken을 생성할 때, 사용자 권한 정보가 올바르게 전달되는지 확인하세요.

    • 생성된 authenticationToken에 사용자의 권한이 제대로 설정되어야 합니다.
   UsernamePasswordAuthenticationToken authenticationToken = 
       new UsernamePasswordAuthenticationToken(memberDTO, pw, memberDTO.getAuthorities());

2. CustomSecurityConfig 설정 확인

  1. @EnableMethodSecurity 설정: 이미 @EnableMethodSecurity를 사용하고 계시지만, 꼭 CustomSecurityConfig 내의 다른 설정도 적절하게 되어 있는지 확인하세요.

3. 기타 확인 사항

  1. 토큰 발급 시 역할 정보 포함: JWT 토큰을 발급할 때 claims에 사용자의 권한 정보가 포함되어야 합니다. 이 정보가 빠져 있는 경우, @PreAuthorize 검증이 실패할 수 있습니다.

  2. HTTP 헤더 설정: Postman으로 요청을 보낼 때 Authorization 헤더에 Bearer 토큰이 제대로 포함되어 있는지도 확인하세요. 토큰의 형식이 잘못되면 인증에 실패할 수 있습니다.

참고 답변 링크

추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서도 답변을 확인하시고 추가적인 도움을 드릴 수 있을 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해 드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏

tobot222님의 프로필 이미지
tobot222

작성한 질문수

질문하기