쿠키 & 세션
쿠키는 로그인할 때 잘 안쓴다!
대안
쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰을 노출하고, 서버에서 토큰과 사용자 id를 매핑해서 인식한다. 서버에서 토큰을 관리
토큰은 해커가 임의의 값을 넣어도 찾을 수 없도록 예상 불가능해야한다.
해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 해당 토큰의 만료시간을 짧게 유지한다. 해킹이 의심되는 경우 서버에서 해당 토큰을 강제로 제거하면 됨
세션
동작 방식
세션 저장소를 만들고 거기서 세션을 관리함
해당 세션 id를 반환하는 식으로 동작
보안 문제 해결
쿠키 값을 변조 가능 → 예상 불가능한 복잡한 세션id를 사용한다.
쿠키에 보관하는 정보는 클라이언트 해킹시 털릴 가능성이 있다, → 세션 id가 털려도 여기에는 중요한 정보가 없다
쿠키 탈취 후 사용 → 해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 세션의 만료시간을 짧게 유지한다. 해킹이 의심되는 경우 서버에서 해당 세션을 강제로 제거
세션 만들기
기능
•
세션 생성 - sessionId 생성, 세션 저장소에 보관할 값 저장, 응답 쿠키 생성해서 전달
•
세션 조회 - sessionId 쿠키의 값으로 , 저장소에 보관한 값 조회
•
세션 만료 - 세션 저장소에 보관한 sessionId와 값 제거
HttpSession 객체를 쓰면 편하다.
//세션 설정
HttpSession session = request.getSession();
session.setAttribute(SessionConst.LOGIN_MEMBER,loginMember);
//세션 파괴
if(session != null){
session.invalidate();
}
//세션 조회
Member loginMember = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);
or
public String homeLoginV3Spring(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model){
if(loginMember == null){
return "home";
}
model.addAttribute("member",loginMember);
return "loginHome";
}
Java
복사
필터
HTTP 요청 → WAS →필터 → 서블릿 → 컨트롤러
필터는 특정 URL 패턴에 적용할 수 있다. /* 이라고 하면 모든 요청에 필터갖 ㅓㄱ용됨
필터는 체인으로 구성되는데, 중간에 필터를 자유롭게 추가할 수 있다.
로그를 남기는 필터 적용 → 로그인 여부를 체크하는 필터 적용하도록
필터 인터페이스
public interface Filter{
public default void init(FilterConfig filterConfig) throws ServletException{}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
public default void destroy(){}
}
Java
복사
init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출
doFilter(): 고객의 요청이 올 때마다 해당 메서드가 호출, 필터의 로직을 구현
destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 대 호출
필터로 로그 남기기
Filter 인터페이스를 구현한 클래스를 짜고, Override해주면 됨
init, doFilter, destroy 세 개를 구현하면 된다.
필터를 만들었으면, 스프링 부트에 등록해줘야한다.
이 때 FilterRegistrationBean을 사용해서 등록하면 됨.
•
setFilter(new LogFilteR()) - Filter를 등록하기
•
setOrder(1) - Filter Chain의 우선 순위 정하기
•
addUrlPatterns("/*") - 어떤 URL들에 의해서 남길건지.
필터로 인증 만들기
loginCheckFilter()를 만든다.
기능
•
whitelist를 작성해서 필터가 안 돌아가게끔
•
미인증 사용자는 로그인 화면으로 다시 돌아가는데, 이 때 로그인을 하면 원래 진입하려는 방향으로 가는 것
인터셉터
스프링 인터셉터
스프링 MVC가 제공하는 기술
HTTP요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터 → 컨트롤러
스프링 인터셉터는 디스패처 서블릿과 컨트롤러 사이에서 컨트롤러 호출 직전에 호출
스프링 인터셉터에도 URL 패턴을 적용할 수 있는데, 서블릿 URL 패턴과는 다르고, 매우 정밀하게 설정 가능
스프링 인터셉터 인터페이스
public interface HandlerInterceptor {
//컨트롤러 호출 전
default boolean preHandle(HttpServletRequest request, HttpServlet Response response, Object Handler)throws Exception {}
//컨트롤러 끝난 후
default boolean postHandle(HttpServletRequest request, HttpServlet Response response, Object Handler, @Nullable ModelAndView modelAndView)throws Exception {}
//view 반환 후
default boolean afterCompletion(HttpServletRequest request, HttpServlet Response response, Object Handler, @Nullable Exception ex)throws Exception {}
Java
복사
정상 상황
preHandle; 컨트롤러 호출 전 호출 - preHandler의 응답값이 true이면 다음 진행, false이면 더 진행 X
postHandle: 컨트롤러 호출 후에 호출 됨
afterCompletion: 뷰가 렌더링 된 이후에 호출
예외 발생 시
preHandle: 컨트롤러 호출 전에 호출
postHandle: 컨트롤러에서 예외가 발생하면 postHandle은 호출되지 않는다.
afterCompletion: afterCompletion은 항상 호출된다. 이 경우 예외를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력 가능
afterCompletion은 예외가 발생해도 호출 됨
preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
String requestURI = request.getRequestURI();
if(handler instanceof HandlerMethod){
HandlerMethod hm = (HandlerMethod) handler;
}
Java
복사
HandlerMethod
•
어떤 핸들러 매핑을 사용하느냐에 따라 핸들러 정보가 달라진다.
•
스프링을 사용하면 @Controller, @RequestMapping을 활용한 핸들러 매핑을 사용한다.
ResourceHttpRequetHandler
•
@Controller가 아니라 /resources/static와 같은 정적 리소스가 호출되는 경우
•
ResourceHttpRequestHandler가 핸들러 정보로 넘어오기 때문에 타입에 따라서 처리가 필요함.
스프링 인터셉터의 경우 메서드의 호출 시점이 완전히 분리되어있다.
두 메서드가 함께 쓰기 위한 변수를 사용하려면 request.setAttribute()를 이용해야한다.
이 인터셉터는 싱글톤으로 관리되기 때문에, 지역변수를 쓰면 위험함.
스프링의 URL경로
•
? : 한 문자 일치
•
* : 경로(/)안에서 0개 이상의 문자 일치
•
**: 경로 끝까지 0개 이상의 경로(/) 일치
•
{spring} : 경로(/)와 일치하고 spring이라는 변수로 캡처
•
{spring: [a-z]+} : regexp [a-z]+와 일치하고, "spring" 경로 변수로 캡처
•
{*spring} 경로가 끝날때까지 0개 이상의 경로(/)와 일치하고 spring이라는 변수로 캡처
ArgumentResolver
우선 ArgumentResolver란 무엇이냐
파라미터로 날라오는 변수들에 대해 공통적인 작업을 해주는 기능이다.
이런 기능을 컨트롤러마다 하려며 말이 안되니까...
•
어노테이션 생성
•
ArgumentResolver를 어노테이션에 대해서 처리하도록 설정
◦
supportsParameter
◦
resolverArgument