Spring Example: Community #5 스프링 인터셉터

함형주·2023년 1월 5일
0

질문, 피드백 등 모든 댓글 환영합니다.

스프링 인터셉터를 활용하여 자신의 게시글, 댓글 수정/삭제 로직에 접근을 막는 기능을 개발합니다. 요청을 보낸 회원의 id와 요청에 포함된 엔티티의 member_id 와 비교하여 같을 경우에만 컨트롤러가 요청을 받을 수 있도록 개발하겠습니다.

Configurer

Configurer

@Configuration
@RequiredArgsConstructor
public class Configurer implements WebMvcConfigurer {

    private final PostService postService;
    private final CommentService commentService;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PostInterceptor(postService))
                .order(1)
                .excludePathPatterns("/post/add")
                .addPathPatterns("/post/edit/*", "/post/*");

        registry.addInterceptor(new CommentInterceptor(commentService))
                .order(2)
                .addPathPatterns("/post/*/comment/edit/*", "/post/*/comment/*");
    }
}

인터셉터를 등록하고 적용될 URL을 지정합니다.

PostInterceptor

PostInterceptor

@RequiredArgsConstructor
public class PostInterceptor implements HandlerInterceptor {

    private final PostService postService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    	// 1.
        String requestURI = request.getRequestURI();

		// 2.
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UserDetailsImpl userDetails = (UserDetailsImpl) principal;
        Member loginMember = userDetails.getMember();

		// 3.
        int pos = requestURI.lastIndexOf("/");
        Long postId = Long.parseLong(requestURI.substring(pos + 1));

		// 4.
        HandlerMethod method = (HandlerMethod) handler;
        if (method.getMethod().getName().equals("post")) return true;

		// 5.
        Post post = postService.findPostForInterceptor(postId);
        if (!post.getMember().getId().equals(loginMember.getId())) {
            response.sendRedirect("/post");
            return false;
        }
        return true;
    }
}

전체적인 로직은 1. 요청 URI 조회 2. 로그인 Member 조회 3. {post_id} 매핑 4. 이후 호출되는 메서드 조회 5. id 검증 후 반환 으로 이루어집니다.

HanlderInterceptor는 파라미터로 Object handler를 제공합니다. 이 필드를 이용하여 호출되는 컨트롤러와 메서드의 정보에 접근할 수 있습니다.

PostInterceptor에선 호출 메서드의 이름이 "post" 일 경우에는 true를 반환합니다. (post()는 단순 조회 로직이라 id 검증 불필요)

이후 Post의 memberId와 loginMember.getId()를 비교하여 다를 경우 false를 반환하고 "/post"로 리다이렉트 시켜주었습니다.

CommentInterceptor

CommentInterceptor

@RequiredArgsConstructor
public class CommentInterceptor implements HandlerInterceptor {

    private final CommentService commentService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();

        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UserDetailsImpl userDetails = (UserDetailsImpl) principal;
        Member loginMember = userDetails.getMember();

        int pos = requestURI.lastIndexOf("/");
        Long comment_id = Long.parseLong(requestURI.substring(pos + 1));

        Comment comment = commentService.findCommentForInterceptor(comment_id);
        if (!comment.getMember().getId().equals(loginMember.getId())) {
            response.sendRedirect("/post");
            return false;
        }
        return true;
    }
}

PostInterceptor와 거의 동일하고 Objcet handler를 통한 메서드 조회 로직이 빠졌습니다.

다음으로

지금까지 작성했던 코드는 몇가지 문제가 있습니다. 처음에 언급했었던 commentNum, heartNum 컬럼에 관한 문제와 엔티티를 삭제할 때 CascadeType.REMOVE 때문에 발생하는 문제 등이 있는데 이를 개선하겠습니다.

github , 배포 URL (첫 접속 시 로딩이 걸릴 수 있습니다.)

profile
평범한 대학생의 공부 일기?

0개의 댓글