LoginInterceptor
package com.tenco.blog_v3.common.config;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.tenco.blog_v3.common.errors.Exception401;
import com.tenco.blog_v3.common.errors.Exception500;
import com.tenco.blog_v3.common.utils.Define;
import com.tenco.blog_v3.common.utils.JwtUtil;
import com.tenco.blog_v3.user.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
// IoC 를 안한 상태 이다.
public class LoginInterceptor implements HandlerInterceptor {
/**
* 컨트롤러 메서드 호출 전에 실행 되는 메서드 이다.
* @param request current HTTP request
* @param response current HTTP response
* @param handler chosen handler to execute, for type and/or instance evaluation
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String jwt = request.getHeader(Define.AUTHORIZATION);
if(jwt == null || ! jwt.startsWith(Define.BEARER)) {
throw new Exception401("JWT 토큰을 전달해주세요");
}
jwt = jwt.replace(Define.BEARER, "");
try {
User sessionUser = JwtUtil.verify(jwt);
request.setAttribute(Define.SESSION_USER, sessionUser);
return true;
} catch (TokenExpiredException e) {
throw new Exception401("토큰 만료 시간이 지났습니다. 다시 로그인 하세요");
} catch (JWTDecodeException e) {
throw new Exception401("유효하지 않은 토큰입니다");
} catch (Exception e) {
throw new Exception500("서버 오류 : " + e.getMessage());
}
}
/**
* 컨트롤러 실행 후, 뷰가 렌더링되기 전에 실행되는 메서드
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 뷰가 렌더링 된 후 실행되는 메서드
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
WebConfig
package com.tenco.blog_v3.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// @Component // IOC
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired // DI 처리
private LoginInterceptor loginInterceptor;
/**
* 인터셉터를 등록하고 적용할 URL 패턴을 설정하는 메서드이다.
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 로그인 인터셉터 등록
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/**") // 인터셉터를 적용할 경로 패턴 설정
.excludePathPatterns("/board/{id:\\d+}");
// 인터셉터 적용에서 제외할 URL 패턴 설정
// /board/1, /board/33 <-- 로그인 인터셉터에서 제외
// \d+ 숫자 하나 이상을 의미하는 정규 표현식 패턴
// 관리자용 인터셉터 등록
}
}
BoardController
// 게시글 전체 조회
@GetMapping({"/", "/boards"})
public ResponseEntity<List<BoardResponse.ListDTO>> list() {
return ResponseEntity.ok(boardService.getAllBoards());
}
BoardService
/**
* 모든 게시글 조회 서비스
*/
// 응답 타입 변경
public List<BoardResponse.ListDTO> getAllBoards() {
// 게시글을 ID 기준으로 내림차순으로 정렬해서 조회 해라.
Sort sort = Sort.by(Sort.Direction.DESC, "id");
List<Board> boards = boardJPARepository.findAll(sort);
// 문법 공부해보기
return boards.stream().map(BoardResponse.ListDTO::new).toList();
}
BoardResponse
package com.tenco.blog_v3.board;
import lombok.Getter;
import lombok.Setter;
public class BoardResponse {
@Getter
@Setter
public static class DTO {
private int id;
private String title;
private String content;
// DTO 사용시 사용자 정의 생성자
public DTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
}
}
// 게시글 상세보기 응답
// 게시글 상세보기 - 댓글 정보
// 게시글 목록 보기 화면을 위한 DTO 클래스 만들어보기
@Getter
@Setter
public static class ListDTO {
private int id;
private String title;
public ListDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
}
}
}
도전 과제 게시글 셍세보기 만들기
UserResponse DTO 설계
UserController 수정
/**
* 게시글 상세보기 처리 메서드
* 요청 주소: **GET http://localhost:8080/board/{id}**
*
* @param id 게시글의 ID
* @param request HTTP 요청 객체
* @return 게시글 상세보기 페이지 뷰
*/
@GetMapping("/boards/{id}")
public ResponseEntity<?> detail(@PathVariable Integer id, HttpServletRequest request) {
User sessionUser = null;
// api 경로가 아니기 때문에 jwt 토큰 있는지 여부 검사 해보자
String authorizationHeader = request.getHeader(Define.AUTHORIZATION);
if(authorizationHeader != null && authorizationHeader.startsWith(Define.BEARER)) {
// 인증된 사용자 이다. (여기 안에 오면)
String token = authorizationHeader.replace(Define.BEARER, "");
try {
sessionUser = JwtUtil.verify(token);
} catch (TokenExpiredException e) {
return ResponseEntity.status(401).body(new ApiUtil<>(401, "토큰 유효시간 만료"));
} catch (Exception e) {
return ResponseEntity.status(401).body(new ApiUtil<>(401, "유효하지 않은 토큰 입니다"));
}
}
// 게시글 상세보기 로직 호출 - 서비스 단에서 수정한 DTO 을 내려줘야 합니다.
// TODO 수정 해야 함
return ResponseEntity.ok(new ApiUtil<>(null));
}
'Spring boot > 개념 공부' 카테고리의 다른 글
JwtUtil 만들어 보기 (0) | 2024.11.08 |
---|---|
JWT란 뭘까? (0) | 2024.11.08 |
RestAPI 컨트롤러 요청과 응답 (1) | 2024.11.08 |
공통 응답 DTO 및 예외 처리 구조 만들기 (0) | 2024.11.08 |
RestAPI 주소 변경 및 인터셉터 수정 (0) | 2024.11.08 |