@Service
public class MemberServiceImp implements MemberService {
@Autowired
private MemberRepository repository;
@Override
public Boolean inValid(String username, String password) {
// 여기서 리파지토리에게 업무를 맡기면 안된다
// 리파지토리에 해당되는 crud만 조회하도록 한다
// repository.findbyId(1L);
Member member = repository.findByNickName(username); // username은 사용자가 만든 아이디
// 멤버 정보가 널이거나, 멤버정보가 있어도 패스워드가 맞지 않으면 리턴시킨다
if (member == null)
return false;
else if (!member.getPassword().equals(password))
return false;
return true;
}
}
한번 서버가 저장을 하고 보내주면 url 달라도 쿠키가 적용될 수 있다.(항상 가져옴. 단 하위페이지에 부여한건 상위페이지에서 가져다 쓸 수 없다)
#️⃣ 서버에서 쿠키 꺼내쓰기
1. 맨땅으로 꺼내기 - 반복문으로 찾아야 한다
//MVC MenuController.java
@RequestMapping("detail")
public String detail(Model model, HttpServletRequest request, @RequestParam String id) {
Long mId = Long.parseLong(id);
Menu menu = service.getById(mId);
System.out.println(menu);
model.addAttribute("menu", menu);
//쿠키는 꺼낼때 덩어리로 꺼내서 찾아야한다는 단점이 있다
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("cookietest")) {
System.out.println("Cookie Name: " + cookie.getName());
System.out.println("Cookie Value: " + cookie.getValue());
break;
}
}
} else {
System.out.println("No cookies found in the request.");
}
return "menu/detail";
}
쿠키 안에 String외에 배열, 엔티티 등을 심을수있을까? 🚫
전달방식 자체가 url 기반의 문자열 ⭕ 이므로 문자열만 가능하다
url 인코딩방식으로 쿠키를 심고 꺼내 쓸때도 디코딩을 해야한다. 만약 스프링 어노테이션인 @CookieValue를 쓴다면 디코딩도 자동으로 됨!
쿠키는 루트페이지에서 전달해야 하위페이지도 적용됨
2. 스프링으로 꺼내기 (@CookieValue)
@RequestMapping("detail")
public String detail(@CookieValue String cookietest, Model model, @RequestParam Long id) {
//HttpServletRequest request --어노테이션으로 뽑으면 서블릿을 불러올 필요가없음
System.out.println(cookietest);
System.out.println("나와라");
Menu menu = service.getById(id);
model.addAttribute("menu", menu);
//쿠키는 꺼낼때 덩어리로 꺼내서 찾아야한다는 단점이 있다
// Cookie[] cookies = request.getCookies();
//
// if (cookies != null) {
// for (Cookie cookie : cookies) {
// if (cookie.getName().equals("cookietest")) {
// System.out.println("Cookie Name: " + cookie.getName());
// System.out.println("Cookie Value: " + cookie.getValue());
// break;
// }
// }
// } else {
// System.out.println("No cookies found in the request.");
// }
return "menu/detail";
}
👉 이때 파라미터 내 순서에서 @CookieValue가 마지막이라면, 출력순서도 마지막이 되어야한다. 다른 파라미터 출력값보다 쿠키출력이 먼저 나오면 콘솔에 찍히지않음! 파라미터를 한번에 받아서 처리한다고 생각했는데 파라미터도 순서대로 받아서 출력처리한다는걸 새삼깨달았다...
#️⃣ 쿠키 사용 제약 조건
1) 쿠키가 적용될 범위 적용 (세션은 불가)
Cookie cookie = new Cookie("cookietest", "octap");
if (request.getCookies() == null) // 쿠키가 하나라도 없을때 응답할때 쿠키를 부여한다
response.addCookie(cookie);
cookie.setPath("/menu"); //쿠키가 지정될 경로(범위)를 지정할 수 있다
cookie.setMaxAge(1000000000); // 쿠키 생존시간 설정 (초단위이므로 계산해서 넣어야 함)
yamul에서 쿠키의 세션을 저장할 수 있다 (이때 설정키워드는 스프링부트 버전에 따라 다르며, 접미사를 붙이지 않으면 초단위임)
쿠키의 생존기간을 지정하지 않으면 세션과 동일하게 움직인다
2) 사용자 디스크에 저장된다
✔️ 쿠키는 기본적으로 현재 브라우저가 관리하는 프로세스 메모리에 저장된다.
👉 따라서 모든 브라우저를 다 닫아야 세션 키를 분실한다 (브라우저 하나를 닫는다고 해도 그 내부에 스레드가 수십개 움직이고있어서 프로세스가 죽는건 아니다)
✔️만약 쿠키의 저장기간을 1년이라고 하면 1년동안 컴퓨터를 끄지 않는이상 프로세스에 유지하기 힘드므로 이런경우는 디스크에 저장한다.
✔️ 쿠키는 클라이언트 디스크에 저장되므로 사용자에게 허용설정을 요청한다.
(* 어플리케이션은 모든 사용자를 위한 공간이라 덮어쓰기가 되므로 인증정보는 나만을 위한 공간인 세션이나 쿠키를 사용해야한다)
✅ 로그인 페이지 만들기
로그인에 들어가는경우 1) 로그인하려는 의도 2) 페이지를 보려고 했는데 로그인부터 하라고 요청받는 경우
@Controller
@RequestMapping("/member")
public class MemberController {
@GetMapping("index") //회원들이 들어가는 인덱스
public String login(HttpSession session) {
//로그인페이지에서 담아주면 거기있는 세션을 가지고 검증
Object username_= session.getAttribute("username");
// 회원들 인덱스에 접속하려고 할 때- 너 인증은 하고 왔니? 안했으면 인증하고 와
if (username_ ==null)
return "redirect:/user/login";
return "member/index";
}
//UserController
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("login")
public String login() {
//여기는 데이터 필요없이 로그인 한다는 내용만있으므로 서비스가 필요없다
return "user/login";
}
//유저네임과 패스워드를 파라미터로 입력받음 url은 login인 postMapping controller
// 로그인을 처리하는 실질적인 코드
@PostMapping("login")
public String login(String username, String password) {
// 로그인을 처리하는 실질적인 코드영역
// 두가지 경로.
// 1) 가다가 걸려서 왔으면 인증하고 거기로 다시 return
// 2) 자발적으로 로그인 하러 왔으면 로그인 후 이동하는 위치 지정해주기
if (service.inValid(username, password)) {
session.setAttribute("username", username);
// 포스트 요청으로 온 사람은 뷰페이지로 가면 안되고 무조건 리디렉션
return "redirect: /user/index";
}
return "redirect:/user/login";
}
}
html과 css만 다루는 환경에서는 다른메뉴를 클릭할 경우 ▶ 서버에요청 ▶ 서버에서 다른 페이지로 연결해줌. ▶요청에 대해서 그때그때 서블릿이 생겼었음.
3. 세션이 생긴 배경
서버에서 서블릿들은 생겼다 사라지지만 인증정보가 사라지면 안됨. 이때 활용할 수 있는 '계속 존재하는 공간'은 어플리케이션(서버에서 사용하는 전역변수공간)과 세션임
이때 세션은 공간이라 생각하면 안됨. 정확학는 세션== '기간'을 뜻한다.
웹은 세션이란 기간을 두고 ,나랑 대화하는 사용자가 있다, 없다를 생각한다.
(사용자가 나를 다시 찾을지 여부에 대한 기다림의 기간. 여러 클라이언트로부터 페이지 요청을 받으므로 한 사용자에게 무한대로 접속 시간을 제공할 수 없다 & 보안문제!)
4. 세션이 기간인 이유
서버는 클라이언트 한명이 다섯번 요청한건지, 다섯명이 한번씩 요청한건지 알 수가 없음 ▶ 따라서 사용자를 위한 저장공간을 마련해야 한다.(해당 사용자가 하는 행위, 프로필정보 등을 저장하기 위해 전용공간인 세션을 설정할 수 밖에 없다) ▶ 사용자를 식별하는 방법이 필요하다 ▶ 공유기 ip를 가지고 식별이 불가함(사설아이피로 요청할 일이 없고 같은 공유기를 쓰면 그 집 컴퓨터는 다 같은 ip를 가진다) ▶ 서버로부터 식별자가 발급된다 (SID발급)
세션 == 사용기간 (자원 사용을 허락받은 시간)
서버의 (세션)공간을 사용할 수 있다 (*사용할 자원이 있어야 한다)
공간을 사용하기 위해서는 (세션)키가 필요하다. (이 키는 보안키/세션아이디/SID로도 불린다)
톰캣의 default 세션 = 20분
세션 타임아웃을 따로 설정할 수도 있다.
SID를 발급받은 클라이언트는 접속할때마다 해당 저장공간을 정해진 시간동안 사용할 수 있다. (ex. 세션이 유지되는 동안 페이지를 넘어다니며 장바구니에 값을 저장해둬도 초기화가 되지않는다)
#️⃣ Session 생성해보기
@Controller
@RequestMapping("/")
public class HomeController { //기본값으로 string을 설정해서 세션에 전달해봄
@RequestMapping("index")
public String index( @RequestParam (defaultValue="octap")String hello, HttpServletRequest request) {
//서블릿이 다 죽어도 세션저장소는 키를 가진 사람만 쓸 수 있는 전역 공간이므로 죽지 않는다!
HttpSession session = request.getSession();
session.setAttribute("test",hello);
return "index";
}
}
처음 접속할때 서버로부터 cookie를 받는다재접속할때는 쿠키값을 가지고 request한다
@Controller
@RequestMapping("/menu")
public class MenuController {
@Autowired
private MenuService service;
@RequestMapping("list")
public String list(Model model, HttpServletRequest request) {
HttpSession session = request.getSession();
// 다른코드 생략
System.out.println(session.getAttribute("test")); // 다른컨트롤러에서 넣은 test의 값이 나온다
return "menu/list";
}
👉 세션을 생성하지않으면 똑같이 접속해도 SID를 받질 않음! 개발자도구의 어플리케이션으로 가도 cookie를 확인할 수 없음!
👉 세션이 살아있는 동안은 어느 서블릿에서든 (다른 페이지에서도) 세션을 꺼내볼 수 있다. ▶ 세션키(SID)만 가지고 다니면 된다. (만약 세션키를 분실한다면 저장해놓은건 모두 잃어버림) -- 이때 세션키도 쿠키임!
#️⃣ 쿠키 개념
(** 개인화된 저장소는 쿠키와 세션으로 볼 수 있다.)
쿠키는 브라우저에 or 클라이언트에 저장하는 값.
서버가 저장하라고 알려준 값. (접속할때 처음만 설정되고 새로고침하면 사라짐)
캐비넷 키와 동일.
서버에 접속할때마다 가져가야함.
전체적으로 SID와 설명이 유사한것같은데, SID도 쿠키에 담겨서 이동된다!
#️⃣ 쿠키 생성하기
쿠키는 클라이언트가 가지고 있는 것.
응답헤더에 set cookie로 들어감으로써 처음으로 받고, 페이지에 request할 때마다 Cookie를 가져간다.
그 이후로는 서버에서 response할때 cookie를 전달해줄 필요가 없다
@RequestMapping("list")
public String list(Model model, HttpServletRequest request, HttpServletResponse response) {
Menu menu = Menu.builder().engName("ame").build();
//코드생략
Cookie cookie = new Cookie("cookietest", "octap");
if (request.getCookies() ==null) // 쿠키가 하나라도 없을때 응답할때 쿠키를 부여한다
response.addCookie(cookie);
if(request.getCookies().length<0) //쿠키 최초 전달 후, response에 재전달하지 않기 위한 검증
response.addCookie(cookie);
return "menu/list";
}
// 위의 list페이지에서 쿠키를 발급후, 상위페이지인 인덱스에서 쿠키를 찾아보았다
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println("Cookie Name: " + name);
System.out.println("Cookie Value: " + value);
}
} else {
System.out.println("No cookies found in the request.");
}
👉 하위페이지(/menu/list) 에서 쿠키를 발급했을때, 상위페이지(/index)에서는 쿠키를 인식하지 못한다.
👉 list에 다시 재접속해보면 기존 쿠키가 인식되면서 값을 찾을 수 있다.
👉 반대로 index에서 쿠키가 발급되면 list에 접속해도 쿠키를 확인할 수 있다.
👉 세션은 상하페이지 상관없이 서블릿을 통해 공유된다. (session.setAttribute(), session.getAttribute());