슬기의 TIL - 2023.05.04
주특기 3주차 시험을 보았다.
API에 맞춰 CRUD 기능을 가진 중고마켓 서버를 만드는 것이었고, 금방 풀어서 제출했다. (결과는 10점)
소스 코드는 깃헙에 있다.
https://github.com/limseulki/hanghaemarket
오늘 푼 알고리즘 문제들은 난이도가 낮다고 느껴져서 여러개 풀었다.
대망의 코드 리펙토링..
어제 새벽까지 팀원분이랑 같이 고민했는데, 아직도 같은 문제로 여러명이 고민중이다.
문제는
'securityConfig에서 permitAll 해주지 않았을 때는, AccessToken 없이(또는 공백으로) 게시물을 작성하려고 하거나, 조회하려고 하면 state는 403이 뜨면서, 클라이언트 쪽으로 반환되는 에러 메시지가 하나도 없다. 서버쪽은 아무 에러 메시지도 뜨지 않는다.
securityConfig에서 permitAll 해주면, 클라이언트 쪽은 똑같이 403이 뜨고 공백이고, 서버쪽에는 userdetails가 없다고 nullpointer 예외가 발생했다.'
우선 permitAll로 해준 상태에서 발생하는 예외를 잡아보기 위해, controller의 createPost 부분에서 userdetails가 null일 때 예외를 던져주었다. 그렇게 하니까 클라이언트 쪽에 custom 해준 예외 메시지와 상태가 나왔다.
그런데, 문제는 모든 게시글 작성, 수정, 삭제, 댓글..... 등 모든 작업들에 예외를 걸어주어야 한다는 것이다.
뭔가 이상했다.
그리고 permitAll을 하지 않고,
회원가입, 로그인, 전체 게시글 조회, 선택 게시글 조회만 토큰 검증 없이 접근할 수 있도록 하고 싶고,
나머지 작업들은 로그인을 해야 이용할 수 있게 하고 싶다.
그렇다면 securityConfig는 손대지 않고, 다른 곳에서 AccessToken이 없을 때 예외 처리를 해주어야 한다는 것이다.
JwtAuthFilter에서 토큰 검증하는 로직이 있어서 거기에 access token이 null 일 때, 예외 처리를 해보았다.
똑같이 custom한 대로 출력이 되었다.
그런데...!!
get을 해서 전체 게시글 조회를 해도 토큰이 없다고 나왔다..
회원가입, 로그인도 안된다.
토큰이 없어도 허용되어야 하는 작업들이 안된다.
그런데 회원가입하면 DB에 쌓인다.
작업은 되면서 AccessToken이 없다는 메시지가 출력되는 거다.
(else 처리를 해놓은 게 무조건 돌고 나오는 것..!)
궁금한 것!!!
모든 필터는 무조건 거칠 수 밖에 없는 건가?
기본으로 403 Fobidden 상태가 나오는데, 클라이언트에 AccessToken이 없다는 예외를 꼭 직접 만들어서 알려줘야 하는건가?
이미 예외처리가 잘 되고 있는데, postman에서 보여지지 않는 건 아닐까?
WebSecurityConfig에서 예외처리 하는 부분을 추가했다.
http.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.getReasonPhrase());
}
});
403 Forbidden으로 나오길래 HttpStatus를 Bad_Request로 바꿔보았다.
그랬더니 400 Bad request로 나왔다!!!
결국 서버에서 정하는 상태와 메시지가 클라이언트로 넘어가는 거였다..!
포스트맨에서 그저 빈 칸으로 보였을 뿐...ㅠㅠ
sendError(int, String)이길래 다른 값으로도 바꿔서 넣어보았다.
그리고, 보통은 인증단계 예외는 login 화면으로 바로 보낸다고 해서
sendRedirect도 써봤다. (처음엔 "/login"으로 해봄)
그랬더니 아주 신기한 일이 벌어졌다!!
http.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(403, "클라이언트 에러");
response.sendRedirect("/");
}
});
Body에 HTML이 들어온 거다!
그래서 Preview를 눌러봤는데 이렇게 홈페이지처럼 나왔다!
Message에는 내가 적은 메시지가 들어가 있고
결국 에러는 제대로 던져졌고, 뷰와 연결되면 이렇게 원하는 화면을 출력할 수 있겠다는 생각이 들었다!
길고 긴 장정 끝 해결..ㅠㅠ
+ 저 아래 예외에 있는 메시지들은 response가 commit된 후에 redirect하면 안된다는 말이다.
에러를 던져주거나 페이지를 리다이렉트하거나 둘 중 하나를 선택해야 하는 듯.
에러를 던져주는 걸로 선택!