1. Inteceptor
1-1) 인터페이스로 Interceptor 만들기 (interface HandlerInterceptor)
//인터페이스로 Interceptor 만든경우
public class MyInterceptor01 implements HandlerInterceptor {
// Handler 처리하기 전에 (시스템 외부)
// preHandle만 반환 값이 존재한다.
// return false; 로 하면 preHandle까지만 들어고 막는다. || return true; 인 경우 통과시킨다.
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor01.preHandle");
return false;
}
// Handler 끝난 후에
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor01.postHandle");
}
// ViewResolver에 fowarding이 끝난 경우
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor01.afterCompletion");
}
}
1-2) 상속으로 Interceptor 만들기 (HandlerInterceptorAdapter 을 상속받는다.)
//상속으로 Interceptor 만든경우
//preHandle(), postHandle(), afterCompletion()를 재정의해서 사용한다.
public class MyInterceptor02 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor02.preHandle");
return true;
}
}
1-3) 만든 Interceptor 클래스를 spring-servlet.xml 에 등록해주어야한다.
<!-- Interceptors 설정 -->
<mvc:interceptors>
/user/auth로 요청이 들어왔을때 Interceptor 설정
<mvc:interceptor>
<mvc:mapping path="/user/auth" />
<bean class="com.bitacademy.mysite.interceptor.MyInterceptor01" />
</mvc:interceptor>
</mvc:interceptors>
# Interceptor을 활용한 Login, Logout Security 만들 수 있다. (활용예제)
- [ LoginInterceptor.java ]
: UserController 의 @RequestMapping(value="/join", method=RequestMethod.POST) 역할을 한다.
=> 로그인 실패시 redirect 작업 / 로그인 성공시 session에 등록해주는 작업
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//login.jsp 페이지에서 입력한 이메일과 패스워드를 전달한 것을 request로 받는다.
String email = request.getParameter("email");
String password = request.getParameter("password");
UserVo userVo = new UserVo();
userVo.setEmail(email);
userVo.setPassword(password);
UserVo authUser = userService.getUser(userVo);
//로그인 인증 실패한경우
if(authUser == null) {
response.sendRedirect(request.getContextPath() + "/user/login?result=fail");
return false;
}
//로그인 인증 성공한 경우
//session 처리
HttpSession session = request.getSession(true);
session.setAttribute("authUser", authUser);
response.sendRedirect(request.getContextPath());
return false;
}
- [LogoutInterceptor.java]
: @RequestMapping("/logout") 역할을 한다.
=> 로그아웃시 세션 지우고 세션 비활성화 작업
public class LogoutInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
// 로그아웃 처리
if(session != null) {
session.removeAttribute("authUser"); //세션 지우고
session.invalidate(); //세션 비활성화(세션 삭제)
}
response.sendRedirect(request.getContextPath());
return false;
}
}
- [spring-servlet.xml]
</mvc:interceptors>
<!-- login interceptor 등록 -->
<mvc:interceptor>
<mvc:mapping path="/user/auth" />
<bean class="com.bitacademy.mysite.security.LoginInterceptor" />
</mvc:interceptor>
<!-- logout interceptor 등록 -->
<mvc:interceptor>
<mvc:mapping path="/user/logout" />
<bean class="com.bitacademy.mysite.security.LogoutInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
2. Annotation 을 이용한 Security (@Auto)
예제상황: 회원정보를 수정하는 /update 요청이 들어왔을때 Security
2-1) Auth 어노테이션 파일 생성
[Auth.java]
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Auth {
public Role role() default Role.USER;
}
2-2) [UserController.java]
: @Auth를 메서드(컨트롤러)에 선언 해줌으로써 /update 요청시 AuthInterceptor 를 수행할 수 있게한다.
@Auth
@RequestMapping(value="/update", method=RequestMethod.GET)
public String update(HttpSession session, Model model) {
// 접근제어
UserVo authUser = (UserVo)session.getAttribute("authUser");
Long no = authUser.getNo();
UserVo userVo = userService.getUser(no);
model.addAttribute("userVo", userVo);
return "user/update";
}
2-3) [AuthInterceptor.java]
: /update 를 요청한 Client 의 UserVo 정보를 확인하여 Session에 authUser가 있다면 return true;
없으면 return false; 하는 Interceptor 이다.
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//1. Handler 종류 확인해 본다.
// DeafultServletHandler가 처리하는 경우(보통, assets의 정정 자원 접근) 통과시켜준다.
if(handler instanceof HandlerMethod == false) {
return true;
}
//2. Handler Method(컨트롤러) 인 경우 casting 해준다.
HandlerMethod handlerMethod = (HandlerMethod)handler;
// 3. 클라이언트가 요청한 url 에 해당하는 Method(컨트롤러)에 @Auth 달려 있는지 확인하기
Auth auth = handlerMethod.getMethodAnnotation(Auth.class);
// 4. 클라이언트가 요청한 url 에 해당하는 Method(컨트롤러)에 @Auth가 안달려 있으면
// return true; (패스시켜준다.)
if(auth == null) {
return true;
}
// 5. @Auth가 달려 있는 Method(컨트롤러) 경우에는 인증(Authetication) 여부 확인
HttpSession session = request.getSession();
if(session == null) { // 세션이 없는 경우 돌려보낸다.(로그인 하는 페이지로)
response.sendRedirect(request.getContextPath() + "/user/login");
return false;
}
// 6. 세션이 있는 경우에는
UserVo authUser = (UserVo)session.getAttribute("authUser");
if(authUser == null) { // 인증이 없는 경우 돌려보낸다.(로그인 하는 페이지로)
response.sendRedirect(request.getContextPath() + "/user/login");
return false;
}
// 여기까지 통과한 경우는 세션에 authUser가 있는 경우임으로 통과시켜준다.
return true;
}
}
2-4) [spring-servlet.xml] 에 AuthInterceptor 등록
: 모든 경로에 AuthInterceptor을 하도록 하는데, 3개의 url만 제외 (/assets/** || /user/auth || /user/logout)
</mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/assets/**" />
<mvc:exclude-mapping path="/user/auth" />
<mvc:exclude-mapping path="/user/logout" />
<bean class="com.bitacademy.mysite.security.AuthInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
3. Annotation 을 이용한 Security (@AuthUser 파리미터)
UserController의 update() 컨트롤러에서 authUser을 session을 통해서 불러오는 방법으로 접근제어 했었다.
=> Argument Resolver 라는 방법을 사용해서 update() 컨트롤러에 session에 있는 authUser를 매개변수로
전달하는 것을 만들 수 있다.
* Argument Resolver 란,
사용자가 컨트롤러의 메서드 인자값으로 임의의 값을 전달하려할때 사용된다.
(예, 세션에 저장되어 있는 값 중, 특정 이름의 값을 메서드 인자로 전달한다.)
3-1) AuthUser 어노테이션 파일 생성
[AuthUser.java]
@Retention(RUNTIME)
@Target(PARAMETER)
public @interface AuthUser {
}
3-2) AuthUserHandlerMethodArgumentResolver 클래스 생성 (HandlerMethodArgumentResolver 를 상속)
: AuthUser에 대한 Argument Resolver를 만든다.
[AuthUserHandlerMethodArgumentResolver.java]
//@AuthUser 파라미터 어노테이션을 검사해서 처리하는 Argument Resolver 작성
public class AuthUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
// @AuthUser 검사하는 메서드
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 1. 요청한 파라미터에 @AuthUser 달려 있는지 확인하기
AuthUser authUser = parameter.getParameterAnnotation(AuthUser.class);
// 2. 요청한 파라미터에 @AuthUser 가 안붙어 있는 경우 패스시켜준다.
if(authUser == null) {
return false;
}
// 파라미터 타입이 UserVo가 아니면 ... 패스시켜준다.
if(!parameter.getParameterType().equals(UserVo.class)) {
return false;
}
return true;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//UserVo 타입이 아니거나, @AuthUser 파라미터가 아닌 경우 UNRESOLVED 시켜준다.
if(!supportsParameter(parameter)) {
return WebArgumentResolver.UNRESOLVED;
}
//여기서부터는 @AuthUser 파라미터이면서 UserVo 타입이라는 이라는 것
//webRequest 로 파라미터를 받는 이유는 Spring이 톰켓 외 was에도 사용될 수 있기때문에 범위를
//넓혀서 매개변수로 보낸것
//우리는 톰캣임으로 HttpServletRequest로 casting 해서 사용하면 된다.
HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest();
HttpSession session = request.getSession();
if(session == null) {
return null;
}
return session.getAttribute("authUser");
}
}
3-3 [spring-servlet.xml] 에서 argument resolver 등록해주어야한다.
<!-- argument resolver -->
<mvc:annotation-driven>
<mvc:argument-resolvers>
bean class="com.bitacademy.mysite.security.AuthUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
'비트교육센터[전문가반]' 카테고리의 다른 글
Paging 처리 [Spring] (0) | 2021.05.04 |
---|---|
Spring MVC [비트교육센터] _ 복습04 _ API 전용 컨트롤러 (0) | 2021.04.24 |
Spring MVC [비트교육센터] _ 복습03 (0) | 2021.04.22 |
Spring MVC [비트교육센터] _ 복습02 (0) | 2021.04.21 |
Spring MVC [비트교육센터] _ 복습01 (0) | 2021.04.21 |