프로젝트 진행 중 컨트롤러의 메서드가 로그인 여부를 확인하는 부가기능을 동시에 처리하는 경우가 존재한다.
이런식으로 반복되는 로직을 AOP,Interceptor,Filter 등을 통해 반복되는 부가기능을 공통적으로 처리할 수 있다.
로그인 확인이 필요한 경우
프로젝트를 진행하다가 보면 로그인 없이 접근 가능한 페이지가 있고 로그인을 한 경우에만 접근이 가능한 페이지가 존재한다.
예를들어 마이페이지,비밀번호 변경,상품 등록하기 등이 있다.
Interceptor를 적용하기 전 로그인 확인 과정
- 세션에서 현재 로그인된 사용자의 정보를 꺼내온다.
- 세션에서 꺼낸 값이 Null이라면 , 해당 사용자는 로그인을 하지 않은 상태이므로 401 UNAUTHORIZED를 반환한다.
- 만약 정상적으로 session에서 로그인 정보를 꺼낼수 있다면 200 OK 를 반환한다.
controller
|
1
2
3
4
5
6
7
|
@GetMapping("/my-info")
public ResponseEntity<UserInfoDto> myInfo() {
String currentUser = sessionloginService.getLoginUser();
UserInfoDto userInfoDto = userService.getUserInfo(currentUser);
return ResponseEntity.ok(loginUser);
}
|
cs |
service
|
1
2
3
4
5
6
7
|
public String getLoginUser() {
String userId = session.getAttribute(USER_ID);
if(userId == null) {
throw new UnauthenticatedUserException();
}
return userId;
}
|
cs |
이제 이 과정을 Interceptor를 적용해서 해당 메소드가 자신의 핵심 기능만 집중할 수 있도록 리펙토링 해볼것이다.
어노테이션 생성
|
1
2
3
4
|
@Retention(RUNTIME)
@Target(METHOD)
public @interface LoginCheck {
}
|
cs |
- @LoginCheck : 현재 사용자의 로그인 여부를 확인한다.
- @Retention: 메모리를 어느 시점까지 가져갈지 여부 설정
- @Target : 해당 어노테이션이 어느 위치까지 사용될지 지정한다.
Interceptor 정의
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
@Component
@RequiredArgsConstructor
public class LoginCheckInterceptor implements HandlerInterceptor {
private final SessionLoginService loginService;
//컨트롤러 메서드 실행되기전
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
LoginCheck loginCheck = handlerMethod.getMethodAnnotation(LoginCheck.class);
if (loginCheck == null) {
return true;
}
if (loginService.getLoginUser() == null) {
throw new UnauthenticatedUserException("로그인 후 이용 가능합니다.");
}
}
return true;
}
|
cs |
Interceptor는 preHandler() , postHandler() , afterCompletion() 로 구성되어 있다.
- preHandler() : 컨트롤러 메서드 실행되기전에 실행된다.
- postHandler() : 컨트롤러 메서드 실행 직후, view가 렌더링 되기전 실행됨
- afterCompletion() : view 페이지 렌더링 후 실행
Interceptor는 메서드 실행 직후에 해당 요청을 가로채서 요청을 한 사용자의 로그인 여부를 판단한다.
loginCheck는 해당 Handler에 LoginCheck 어노테이션이 존재하는지 확인한다.
- loginCheck가 null이라면 로그인 없이 접근 가능한 페이지 이므로 true를 반환한다.
- loginCheck가 null이 아니라면 session에서 로그인 정보를 꺼내서 null 여부를 판단한다. null이라면 로그인 후 이용 가능하다는 Exception을 날린다.
- 모든 검증을 통과했다면 로그인이 완료된 상태로 true를 리턴해 다음 작업을 실행한다.
이제 Interceptor를 등록한다.
|
1
2
3
4
5
6
7
8
9
10
11
12
|
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor);
}
}
|
cs |
WebMvcConfigurer는 스프링 부트가 기본적으로 설정한 MVC설정에 추가적으로 기능을 커스터마이징 할 수 있다.(스프링 부트 개발환경에서만 가능)
|
1
2
3
4
5
6
7
|
@LoginCheck
@GetMapping("/my-infos")
public ResponseEntity<UserInfoDto> myPage() {
String currentUser = loginService.getLoginUser();
UserInfoDto loginUser = userService.getUserInfo(currentUser);
return ResponseEntity.ok(loginUser);
}
|
cs |
이제 유저의 로그인 여부를 확인하고 사용자의 ID를 가져오는 Service에서 불필요한 예외처리를 할 필요가 없다.
'Dev > Spring' 카테고리의 다른 글
| [Spring] JPA+Spring으로 카테고리 로직 구현 - 2 (0) | 2021.12.10 |
|---|---|
| [Spring] JPA+Spring으로 카테고리 로직 구현 - 1 (0) | 2021.12.10 |
| [Spring] AOP(Aspect Oriented Programming) (0) | 2021.09.10 |
| ResponseEntity (0) | 2021.08.25 |
| @Transactional (1) | 2021.08.24 |