서론
API를 개발하면서 회원의 권한에 따라 접근 가능 여부를 제어하는 처리를 진행하고 있습니다. 이를 위해 단순하게 Interceptor를 활용하여 Annotation을 사용하여 권한을 체크하고, 해당 권한을 가진 사용자만 접근할 수 있도록 구현하려고 합니다.
인터셉터는 웹 애플리케이션에서 클라이언트의 모든 요청을 가로채고 처리하는데 사용되는 기능입니다.
Interceptor를 활용하여 요청이 처리되기 전에 먼저 사용자의 권한을 체크하고, 그에 맞추어 접근 여부를 결정합니다.
이때 Annotation은 메서드 레벨에 적용되며, 각 핸들러 메서드에 필요한 권한 정보를 Annotation에 작성합니다. 저는 @CheckRole과 같은 커스텀 Annotation을 만들어서 사용할 것입니다.
Interceptor는 요청을 처리하는 과정에서 해당 Annotation을 확인하고, 사용자가 해당 권한을 가지고 있을 경우에만 요청을 허용합니다. 권한을 가지고 있지 않은 사용자의 경우 접근이 제한됩니다.
Filter와 Interceptor에 대해 아래와 같이 정리해보았습니다.
https://passionfruit200.tistory.com/428
본론
1. CheckRole.class
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckRole {
RoleType[] roles() default {RoleType.USER};
}
- 핸들러 메서드에 접근 권한을 체크하기 위한 정보를 명시합니다.
- RoleType 배열을 매개변수로 받으며, 기본적으로 RoleType.USER 권한이 설정되어 있습니다.
2. CheckRoleInterceptor.class
@Component
@Log4j2
@RequiredArgsConstructor
public class CheckRoleInterceptor implements HandlerInterceptor {
private final JWTUtil jwtUtil;
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
/**
* Description : preHandler함수는 데이터가 들어오기전에 먼저 실행되는 함수입니다.
* HandlerMethod ( @Controller, @RequestMapping ) 인지 확인합니다.
* HandlerMethod에 @CheckRole 어노테이션이 존재하는지 확인합니다. 존재하지않는다면 현재 Interceptor를 종료시킵니다.
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
CheckRole checkRole = handlerMethod.getMethodAnnotation(CheckRole.class);
if(checkRole == null) return HandlerInterceptor.super.preHandle(request, response, handler);
RoleType[] annotationRoleType = checkRole.roles();
//실패했다면 종료
if(checkAuthHeader(request, annotationRoleType) == false) throw new AuthenticationException("No Roles");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
- CheckRoleInterceptor는 HandlerInterceptor를 구현한 클래스로, 웹 요청이 처리되기 전에 사용자의 권한을 확인하여 접근 여부를 결정합니다.
- 모든 로직은 어떻게 회원 권한을 인증하냐에 따라 달라지므로, 본인의 로직에 맞게 prehandle 함수에 넣으시면 됩니다.
3. WebMvcConfig.class
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
private final CheckRoleInterceptor checkRoleInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// WebMvcConfigurer.super.addInterceptors(registry);
registry.addInterceptor(checkRoleInterceptor);
}
}
- WebMvcConfig 클래스에서 CheckRoleInterceptor 인터셉터를 등록합니다.
- 이를 통해 인터셉터가 웹 애플리케이션에서 요청을 가로채고 권한을 체크할 수 있게 됩니다.
4. MemberController.class
@CheckRole(roles = {RoleType.USER})
@GetMapping(value ="/{member_no}")
public ResponseEntity<MemberDTO> read(@PathVariable("member_no") long member_no){
log.info("-------------------read----------------------");
log.info(member_no);
return new ResponseEntity<>(memberService.get(member_no), HttpStatus.OK);
}
- MemberController 클래스의 핸들러 메서드에 @CheckRole 어노테이션을 등록하여 접근 권한을 설정합니다. 이렇게 설정된 핸들러 메서드는 해당 권한을 가진 사용자만 접근할 수 있게 됩니다.
마무리
이제 JWT를 사용하여 회원의 권한을 인증하고, @CheckRole 어노테이션을 통해 사용자의 권한을 확인하여 해당 권한을 가진 사용자만 원하는 API에 접근할 수 있게 됩니다