스프링 2-24 ~ 2-26

서현우·2022년 7월 3일
1

스프링의정석

목록 보기
66/85

세션(Session)이란?

  • 서로 관련된 요청과 응답들을 하나로 묶은 것 - 쿠키를 이용
    (요청은 원래 서로 독립적(서로 관계없음))
  • 브라우저마다 개별 저장소(session 객체)를 서버에서 제공.
    (쿠키를 이용하므로 브라우저와 서버는 1:1 관계)

브라우저에서 서버로 요청을 보내면, 서버에서 무조건 세션객체(저장소)를 만들어서 세션ID를 응답메세지로 브라우저에 보내고 브라우저에는 쿠키가 저장된다.
그 다음부터는 요청에 쿠키(세션 ID)를 포함해서 서버로 보낸다. 즉 요청들은 이 세션이 종료되기 전까지, 하나의 세션아이디로 묶이게 되고, 같은 세션 저장소를 사용할 수 있게 된다.
세션이 종료되면 세션 저장소는 자동으로 제거된다.

쿠키를 생성하지 못하게 브라우저에서 막는 경우도 있으므로, 첫 요청이 오면 서버에서는 JSESSION ID를 URL에 붙여서 보내는 것과
응답 헤더로 보내는 것 두 가지를 둘 다 한다. 그다음부터는 쿠키를 허용하지 않으면 URL에 붙여서 계속 보내거나, 쿠키를 허용했으면 응답메세지로 보내지 않고, 요청으로 받기만 한다.
따라서 뷰인 jsp에서 링크는 꼭 <c:url>태그를 써야한다.

세션을 종료할 때는 수동종료(invalidate(), 로그아웃), 자동종료(Time out)가 있다.

세션의 종료

  1. 수동 종료
HttpSession session = request.getSession(); //요청에 있는 세션ID로 세션객체를 찾아서 참조한다.
session.invalidate(); //1. 세션을 즉시 종료한다.
session.setMaxInactiveInterval(30*60); //예약 종료(30분 후)(초단위)
  1. 자동 종료(꼭 넣는 것이 좋다)
    web.xml에 태그로 등록한다.(분단위)
<session-config>
	<session-timeout>30</session-timeout>
</session-config>

쿠키 vs 세션

쿠키(Cookie)는 브라우저에 저장하고, 서버에 부담이 없다. 보안에 불리하고, 서버 다중화에 유리하다.
세션(HttpSession)은 서버에 저장하고, 서버부담이 크다. 보안에 유리하고, 서버 다중화에 불리하다.

index.jsp, boardList.jsp

EL로 navibar의 Login을 로그인 되어있으면 Logout으로, 로그인 안되어있으면 Login으로 변경하고,
맵핑된 주소를 로그아웃은 '/login/logout', 로그인은 '/login/login'으로 바뀌게 한다.

<c:set var="loginOutLink" value="${sessionScope.id==null ? '/login/login' : '/login/logout'}"/>
<c:set var="loginOut" value="${sessionScope.id==null ? 'Login' : 'Logout'}"/>

<li><a href="<c:url value='${loginOutLink}'/>">${loginOut}</a></li>

BoardController.java

GET으로 '/board/list'주소로 연결하면, 컨트롤러가 받아서 @GetMapping으로 BOARD로 이동하게 하는데, 먼저 로그인이 되어있는지 확인한다.
로그인이 안되어있으면 redirect로 로그인페이지로 가게 하고, 로그인 되어있으면 boardList.jsp로 이동하게 한다.
로그인체크는 세션객체를 가져와서, 세션에 id가 있는지 확인하고, 있으면 true 없으면 false를 반환한다.

@Controller
@RequestMapping("/board")
public class BoardController {
    @GetMapping("/list")
    public String list(HttpServletRequest request) {
        if(!loginCheck(request))
            return "redirect:/login/login";
        return "boardList";
    }

    private boolean loginCheck(HttpServletRequest request) {
        //1. 세션을 얻어서
        HttpSession session = request.getSession();
        //2. 세션에 id가 있는지 확인. 있으면 true 반환.
//        if(session.getAttribute("id")!=null)
//            return true;
//        else
//            return false;
        return session.getAttribute("id")!=null; //위 4줄과 같다.
    }

LoginController.java

GET으로 '/login/logout'주소로 연결하면, 컨트롤러의 logout이 받아서 세션을 종료하고, 홈으로 이동하게 한다.

POST로 '/login/login'주소를 연결하면, 컨트롤러의 login메서드가 실행된다.
먼저 id와 pwd를 확인하고, 일치하지않으면 redirect로 로그인 페이지로 이동하게 한다.
일치하면 로그인상태를 유지해야 하므로, 세션객체를 얻어와서, 세션객체에 id를 저장한다.
쿠키를 통해 아이디 기억에 체크되어 있으면, 쿠키를 생성하고 응답에 저장한다.
이제 서버가 요청을 받을 때마다 쿠키가 들어있으므로, 로그인페이지의 아이디는 적혀있고, 체크박스는 체크되어있다.
체크박스를 해제하면 rememberId가 false가 되어서 쿠키를 삭제하라는 응답을 보내고, 로그인페이지는 처음상태로 된다.

@GetMapping("/logout")
public String logout(HttpSession session) {
	//1. 세션을 종료
	session.invalidate();
	//2. 홈으로 이동
	return "redirect:/";
}

@PostMapping("/login")
public String login(String id, String pwd, boolean rememberId,
					HttpServletRequest request,  HttpServletResponse response) throws Exception {
	//1. id와 pwd를 확인
	//일치하지 않으면, loginForm으로 이동
	if(!loginCheck(id, pwd)) {
		String msg = URLEncoder.encode("id또는 pwd가 일치하지 않습니다.", "utf-8");
		return "redirect:/login/login?msg="+msg;
	}

	//2. id와 pwd가 일치하면,
	//세션 객체를 얻어와서,
	HttpSession session = request.getSession();
	//세션 객체에 id를 저장.
	session.setAttribute("id", id);

	//rememberId를 확인.
	if(rememberId) {
		//2-1 쿠키를 생성
		Cookie cookie = new Cookie("id", id);
		//2-2 응답에 저장
		response.addCookie(cookie);
	} else {
		//2-1 쿠키를 삭제
		Cookie cookie = new Cookie("id",id);
		cookie.setMaxAge(0); //쿠키를 삭제
		response.addCookie(cookie);
	}
	//2-3 홈으로 이동
	return "redirect:/";
}

Board를 눌러서 로그인 후, 게시판으로 이동

  1. from, to를 찾는다. from은 request.getHeader("refer"), to는 request.getRequestURL()로 얻을 수 있다.
  2. index.jsp에서 Board를 누르면 from이 '/ch2/'이고, to가 '/board/list'이다. 여기서 'board/list'를 LoginController로 가져가야한다.

PerformanceFilter.java

getHeader("referer")로 from을 알 수 있고, getMethod()로 GET/POST를 확인한다.
getRequestURI, getRequestURL로 to를 알 수 있다.

HttpServletRequest req = (HttpServletRequest) request;
String referer = req.getHeader("referer");
String method = req.getMethod();
System.out.print("["+referer+"] -> "+method+"["+req.getRequestURI()+"]");   

BoardController.java

URL재작성을 통해 '/board/list'의 정보를 toURL로 '/login/login'에 전송한다.

@GetMapping("/list")
public String list(HttpServletRequest request) {
	if(!loginCheck(request))
		return "redirect:/login/login?toURL="+request.getRequestURL();
	return "boardList";
}

loginForm.jsp

먼저 text타입으로 BoardController에서 toURL이 잘 들어왔는지 확인하고, hidden으로 변경한다.

<input type="hidden" name="toURL" value="${param.toURL}">

LoginController.java

BoardController에서 받은 toURL값으로 작업.
toURL이 있을 때는 toURL로 redirect하고, index.jsp에서와 같이 toURL이 없으면, '/'로 redirect.

//2-3 홈으로 이동
toURL = toURL==null || toURL.equals("") ? "/" : toURL;
return "redirect:"+toURL;

세션을 시작할까? - session="true" or session="false"?

가능한 세션 유지기간이 짧아야한다.
세션이 이미 있을 때는 true, false 상관없이 계속 유지되지만, 세션이 없을 때 true, false로 세션의 시작할지 페이지마다 정할 수 있다.
즉 세션이 필요없는 JSP화면에는 false로 하고, 이 false는 기존 세션에는 영향을 주지 않는다.
다만 session=false일 때, sessionScope와 pageContext.session은 사용할 수 없다. sessionScope.id를 pageContext.request.getSession(false).getAttribute('id')로 변경해야한다.

따라서 index, loginForm(GET)에서는 session=false로 한다. 이 뜻은 세션을 시작하지 않는다는 것이다.

index.jsp

page의 session을 false로 하고, 이때는 sessionScope.id를 사용하지 못하므로, 변경한다.
그리고 getSession(false)로 세션을 생성하지 않도록 한다.

<%@ page session="false" %>
<c:set var="loginOutLink" value="${pageContext.request.getSession(false).getAttribute('id') ==null ? '/login/login' : '/login/logout'}"/>
<c:set var="loginOut" value="${pageContext.request.getSession(false).getAttribute('id')==null ? 'Login' : 'Logout'}"/>

loginForm.jsp

아직 로그인을 안했으므로, session="false"로 해서 세션을 생성하지 않도록 한다.

<%@ page session="false" %>
profile
안녕하세요!!

0개의 댓글