작성
·
98
·
수정됨
0
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
생략...
SecurityContextHolder.getContextHolderStrategy().getContext().setAuthentication(token);
filterChain.doFilter(request, response);
} catch (Exception e) {
log.info("---------------JWT ERROR!------------");
log.info(e);
log.info(e.getMessage());
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writeValueAsString(Map.of("error", "ERROR_ACCESS_TOKEN"));
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.println(jsonStr);
writer.close();
}
}
강의의 JWT와 @PreAuthorize 이용하기 파트 후반부에 강의처럼 USER권한만 가진 사용자로 ADMIN권한이 필요한 메소드에 접근하니 포스트맨에서 AccessDenied exception이 뜨지않고
catch (Exception e)가 예외를 잡아버려서
{
"error": "ERROR_ACCESS_TOKEN"
}
결과가 이렇게 나옵니다 이미 AccessDenied 핸들러도 시큐리티에 등록 시킨후 입니다
ADMIN권한을 가진 사용자 토큰으로 요청을 보내면 원하는 데이터도 잘 나옵니다
catch로 잡아서 예외를 던질까 시도해봤는데 이유는 모르겠지만 Exception에서만 예외가 잡힙니다ㅠ
그래서 여러가지 해결책을 알아봤는데
첫번째
catch (RuntimeException e) {
log.info("---------------JWT ERROR!------------");
log.info(e);
log.info(e.getMessage());
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writeValueAsString(Map.of("error", "ERROR_ACCESS_TOKEN"));
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.println(jsonStr);
writer.close();
}
이렇게 RuntimeException으로하면
{
"error": "ERROR_ACCESSDENIED"
}
AccessDenied 핸들러가 잘 작동하구요
두번째
SecurityContextHolder.getContextHolderStrategy().getContext().setAuthentication(token);
} catch (Exception e) {
log.info("---------------JWT ERROR!------------");
log.info(e);
log.info(e.getMessage());
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writeValueAsString(Map.of("error", "ERROR_ACCESS_TOKEN"));
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.println(jsonStr);
writer.close();
}
filterChain.doFilter(request, response);
doFilter를 try catch 밖에 두어도 AccessDenied 핸들러가 잘 작동합니다
세번째
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<?> notAuthorized(AccessDeniedException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
RestControllerAdvice로 하면 핸들러가 작동안하긴해도 예외처리가 가능했습니다
근데 문제는 왜 원래코드에서 영상처럼 작동을 안하는지 이유를 모르겠습니다 제가 빠트린부분이 있을까요?
스프링부트 버전도 똑같이 맞춰보기도 했습니다
답변 1
0
질문을 보고 다시 한번 소스 코드를 실행해서 결과를 확인했습니다만 문제가 발생하지 않았습니다.
예제 코드는 해당 섹션의 마지막쪽에 수업자료로 등록되어 있으니 다운로드 받아서 실행해 보실 수 있습니다.
Access Denied는 시큐리티에 관리되는 UserDetails를 통해서 처리되므로
UsernamePasswordAuthenticationToken authenticationToken
= new UsernamePasswordAuthenticationToken(memberDTO, pw, memberDTO.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
authenticationToken의 값이 어떻게 나오는지 확인이 필요합니다.
말씀하신 문제는 작성하신 코드를 보면서 실행해 봐야 원인을 알 수 있을 듯 합니다.
코드를 https://drive.google.com/drive/folders/1ZLHRKaXx8Ou8kZNd1WE6qALxq_wJODXW?usp=drive_link
에 올려주시거나 코드를 접근할 수 있는 방법을 cookie_00@naver.com으로 알려주시면 살펴볼 수 있을듯 합니다.
JWTCheckFilter에서 예외를 잡아서 직접 던지시는게 제일 간단합니다. 강의와 다른 버전이라.. 좀 더 테스트가 필요하긴 하지만 우선 해결책으로.. 예외를 잡아서 던지시면 처리가 되실 겁니다.
SecurityContextHolder.getContextHolderStrategy().getContext().setAuthentication(token);
filterChain.doFilter(request, response);
}catch(ServletException e){
throw e;
} catch (Exception e) {
log.info("---------------JWT ERROR!------------");
log.info(e);
log.info(e.getMessage());
강의에서 사용한 스프링부트 버전이 3.1.5 버전이라 3.1.5로 다운그레이드도 해봤는데 동일한 결과가 타나나더라구요ㅠ
jjwt 버전이 좀더 최신이여서 문제가 되지는 않을거같은데...
해결책으로 주신방법은 AccessDenied 핸들러가 잘 작동합니다
근데 로그창에
이런 로그도 같이뜨네요..
강의 코드 역시 버전 업을 시키니 예외 발생 메시직가 동일하게 나옵니다.
다만 버전업을 시켜도 별도의 추가적인 예외 처리를 하지는 않았습니다.
개인적으로 작성하신 코드의 내부를 좀 더 살펴봐야 원인을 알 수 있을 듯 합니다.
답변감사합니다 프로젝트 파일 db username 과 password만 지우고 드라이브에 올렸습니다 UserDetails 구현은 CustomUserDetails에서 했습니다