SpringBoot [스프링부트] 시작하기(8) Interceptor 만들기
앞서 만들었던 MemberController에 대한 로직들은 로그인이 없어도 호출이 가능했고, 비록 다른 사용자여도 로그인만 하여 세션이 있다면 다른 사용자의 정보를 이용할 수 있었습니다. 이러한 현상을 방지하기 위해 Interceptor를 만들도록 하겠습니다.
Interceptor란?
Controller의 Handler를 호출하기 전, 호출한 후를 가로채서 가공을 할 수 있는 것을 의미합니다.
기본적인 spring Interceptor의 흐름은 아래와 같습니다.

1. MemberInterceptor
@Component @RequiredArgsConstructor public class MemberInterceptor implements HandlerInterceptor { private final UserRepository userRepository; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(false); if(session==null){ response.sendRedirect("/err/member/noUser"); return false; } SessionDto sessionUser = (SessionDto) session.getAttribute(SessionConst.LOGIN_MEMBER); User user = userRepository.findById(sessionUser.getId()).orElseThrow( () -> { throw new CanNotFindUser("해당 유저는 없습니다."); } ); if(sessionUser.getRole()!=ROLE.MEMBER){ response.sendRedirect("/err/member/notAuthority"); return false; } return true; } }
- HandlerInterceptor: preHadler, postHandler, afterHandler 총 3가지를 구현할 수 있지만 저희는 로그인을 하여 세션이 있는지, 역할은 Member인지만 확인하여 Controller로 보내면 되게 때문에 preHandler만 Override 해서 구현합니다.
- response.sendRedirect(): 만약 session이 없다면 로그인 되지 않은 사용자이기 때문에 요청을 /err/member로 redirect 하고, return false를 하여 원래 URI에 도달하지 못하게 합니다.
- sessoion은 있지만 역할이 Member가 아닐 때는 resposen.sendRedirect("/err/member/notAuthority")로 보냅니다.
- 위의 두 조건을 모두 만족한다면 원래 URI을 담당하는 Controller에게 요청이 가게됩니다.
- 유의 사항은 response.sendRedirect를 하여도 밑에 로직들은 계속해서 수행되게 됩니다. 따라서 return false로 바로 밑에 로직들을 수행하는 것을 차단해줘야 합니다.
2. CanNotFindUser
public class CanNotFindUser extends RuntimeException{ protected CanNotFindUser(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public CanNotFindUser() { super(); } public CanNotFindUser(String message) { super(message); } public CanNotFindUser(String message, Throwable cause) { super(message, cause); } public CanNotFindUser(Throwable cause) { super(cause); } }
- MemberInterceptor의 UserRepository에서 혹시나 User가 없는 예외가 터질 것을 대비해서 추가한 예외 클래스입니다.
3. ErrorController
@RestController @RequestMapping("/err") public class ErrorController { @GetMapping("/member/noUser") @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorDto noLogin(){ return new ErrorDto("로그인을 해주세요."); } @GetMapping("/member/notAuthority") @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorDto noAuthority(){ return new ErrorDto("해당 유저는 멤버 권한이 없습니다."); } }
- Interceptor에서 redirect가 발생한 것을 담당하는 Controller입니다.
- 발생한 이유를 담아 클라이언트에게 응답합니다.
4. WebConfig 수정
@Configuration @RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { private final UserRepository userRepository; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new ArgumentResolver()); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MemberInterceptor(userRepository)) .addPathPatterns("/member/**") .excludePathPatterns("/signup","/login"); } }
- addInterceptors를 Override 하여 추가해줍니다.
- addPathPatterns(): Interceptor를 적용할 URI을 명시합니다.
- excludePathPatterns: Interceptor를 적용하지 않을 URI을 명시합니다. /signup, /login은 session이 없어도 사용할 수 있어야 회원가입과 로그인이 가능하므로 예외 패턴에 넣습니다.
5. Postman Test
- 로그인을 하지 않아 session이 없지만 /member/**에 접근을 시도했을 때

MemberInterceptor에서 Session이 없는 것을 확인하여 요청받은 URI가 아닌 Error URI로 redirect 한 것을 볼 수 있습니다.
- 역할이 Member가 아닌 TeamFounder인데 Member URI에 접근했을 때

Member가 아닌 founder로 회원가입을 진행했습니다.

로그인을 하여 session이 생성된 것을 알 수 있습니다.

ROLE이 Member가 아니기 때문에 오류를 반환하는 것을 알 수 있습니다.
6. 추가된 패키지 구성입니다.

지금까지 MemberController에 접근하는 데 있어서 Interceptor로 요청을 가로채 정보를 확인한 후 로그인을 하였는지, Member의 역할을 가졌는지 확인해보았습니다. 다음 포스팅은 Team, League에 관한 Repository, Service, Controller, Interceptor를 만듭니다. 중복되는 내용이 많으므로 빠르게 제작하고 그다음에는 AOP에 관하여 포스팅하겠습니다. 감사합니다.
모든 코드는 아래 링크에서 확인 가능합니다.
https://github.com/rlaehdals/blogProject
GitHub - rlaehdals/blogProject
Contribute to rlaehdals/blogProject development by creating an account on GitHub.
github.com
'SpringBoot > spring 프로젝트 만들기' 카테고리의 다른 글
SpringBoot [스프링부트] 시작하기(10) TeamController, Interceptor, Advice만들기 (0) | 2022.01.17 |
---|---|
SpringBoot [스프링부트] 시작하기(9) Team 내부 로직 만들기 (0) | 2022.01.17 |
SpringBoot [스프링부트] 시작하기(7) ArgumentResolver 만들기 (0) | 2022.01.15 |
SpringBoot [스프링부트] 시작하기(6) MemberController 만들기 (0) | 2022.01.15 |
SpringBoot [스프링부트] 시작하기(5) Member 관련 완성하기 (0) | 2022.01.15 |
댓글
이 글 공유하기
다른 글
-
SpringBoot [스프링부트] 시작하기(10) TeamController, Interceptor, Advice만들기
SpringBoot [스프링부트] 시작하기(10) TeamController, Interceptor, Advice만들기
2022.01.17Member의 Interceptor에는 로그인과 권한만 일치한다면, 모든 요청을 통과시켰습니다. 하지만 안드로이드나, web페이지에서 요청을 할 수 있는 버튼만 제공하지 않는다면 안전할까요?? -> 정답은 아닙니다. 서버의 IP와 URI, 같은 권한을 가진 로그인 사용자가 접근한다면 다른 사용자의 DB를 이용할 수 있게 됩니다. 이러한 상황을 막기 위해 TeamInterceptor에는 검증하는 로직을 추가합니다. MemberInterceptor에도 마찬가지로 추가해야 합니다. 여러분이 실습할 수 있는 시간을 드리기 위해 추가하지는 않겠습니다. 1. TeamController, TeamControllerAdvice @RestController @RequiredArgsConstructor @RequestMa… -
SpringBoot [스프링부트] 시작하기(9) Team 내부 로직 만들기
SpringBoot [스프링부트] 시작하기(9) Team 내부 로직 만들기
2022.01.17Member를 만들던 것과 비슷하므로 추가적인 개념이 있다면 그 구분에 대해서만 설명하겠습니다. TeamFounder = Team의 요구사항과 같다고 할 수 있습니다. TeamFounder는 하나의 Team만 만들 수 있습니다. TeamFounder는 Member가 신청한 리스트를 확인할 수 있으며 수락이 가능합니다. TeamFounder는 Team해체가 가능합니다. TeamFounder는 League 참가 신청을 할 수 있습니다. LeagueHost가 수락을 해야 League에 참가가 완료됩니다. 여러 리그에 신청이 가능하지만 한 League에만 참석이 가능합니다. 1. TeamService, TeamServiceImpl TeamRepository 추가 public interface TeamReposi… -
SpringBoot [스프링부트] 시작하기(7) ArgumentResolver 만들기
SpringBoot [스프링부트] 시작하기(7) ArgumentResolver 만들기
2022.01.15전 시간에 Controller에서 Session을 가져오는 데 있어서 중복 코드가 있었습니다. 해당 코드를 ArgumentResolver로 해결해보겠습니다. ArgumentResolver란? 컨트롤러의 메소드의 인자로 사용자가 임의의 값을 전달하는 방법을 제공할 때 사용합니다. 저희가 활용할 부분은 세션에 저장되어 있는 것을 메소드의 파라미터로 넘겨주는 역할을 하게 됩니다. 1. argumentresolver 패키지 먼저 만듭니다. SessionConst와 SessionDto를 사용하므로 Dto에 있던 것을 옮겨줍니다. 2. ArgumentResolver에 사용될 LoginUser Annotation만들기 @Target(ElementType.PARAMETER) @Retention(RetentionPoli… -
SpringBoot [스프링부트] 시작하기(6) MemberController 만들기
SpringBoot [스프링부트] 시작하기(6) MemberController 만들기
2022.01.15UserController를 만들었던 거 처럼 MemberController를 만들겠습니다. 1. MemberController Controller위에 @RequestMapping("member")을 주면 모든 메소드에 적용됩니다. /member/~~이런식으로 식별됩니다. @PostMapping("/request/{teamId}") public Long requestTeam(@PathVariable(name = "teamId")Long teamId,HttpServletRequest request){ HttpSession session = request.getSession(false); SessionDto sessionUser = (SessionDto) session.getAttribute(SessionC…
댓글을 사용할 수 없습니다.