일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- name=springapplication
- 백준
- Decapsulation
- 네트워크모델
- 페이로드
- wan
- 도커
- springboot
- 오름차순
- SpringApplication
- ubuntu
- 리눅스계열
- 배열빈도수
- dbeaver
- docker
- 도커권한설정
- 리눅스환경
- 유니캐스트
- 디비버
- 백준1946
- 우분투
- 포트포워딩
- 모래시계출력
- instancenotfoundexception
- 브로드캐스트
- jmx
- 포트포워딩 안될때
- javax.management.instancenotfoundexception: org.springframework.boot:type=admin
- 배열최소값최대값
- 배열복사
- Today
- Total
다잘하고싶어
[Spring] 로그인구현5_세션 직접 구현하고 적용하기 본문
세션 직접 구현
1. 세션 생성
2. 세션 조회
3. 세션 만료
1. 세션 생성
@Component
public class SessionManager {
public static final String SESSION_COOKIE_NAME = "mySessionId";
private Map <String, Object> sessionStore = new ConcurrentHashMap<>();
//동시성 문제가 발생할 수 있을 때에는 무조건 ConcurrentHashMap 사용하기
/**
* 세션생성
*/
public void createsSession(Object value, HttpServletResponse response) {
//session id 생성, 값을 세션에 저장
String sessionId = UUID.randomUUID().toString();
sessionStore.put(sessionId, value);
//쿠키 생성
Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
response.addCookie(mySessionCookie);
}
}
mySessionId 입력 후, 상수로 만들기 -> 단축키 : ctrl + alt + C ( option + command + C)
2. 세션 조회
/**
* 세션 조회
*/
public Object getSession(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();//쿠키는 배열로 반환된다.
if (cookies == null) {
return null;
}
for (Cookie cookie: cookies ) {
if (cookie.getName().equals(SESSION_COOKIE_NAME)) {
return sessionStore.get(cookie.getValue());
}
}
return null;
}
위의 코딩을 간단하게 리팩토링하면?
public Cookie findCookie(HttpServletRequest request, String cookName) {
Cookie[] cookies = request.getCookies();//쿠키는 배열로 반환된다.
if (cookies == null) {
return null;
}
//배열을 스트림으로 바꿔줌
return Arrays.stream(cookies)
.filter(cookie -> cookie.getName().equals(cookName))
.findAny()
.orElse(null);
}
(+) FindFirst()와 FindAny()의 차이?
FindFirst() 순서가 중요. 첫번째로 나온 애.
FindAny() 순서와 상관없이 빨리 나온 애.
최종코드
/**
* 세션 조회
*/
public Object getSession(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
if (sessionCookie == null) {
return null; //실패
}
return sessionStore.get(sessionCookie.getValue());
}
public Cookie findCookie(HttpServletRequest request, String cookName) {
Cookie[] cookies = request.getCookies();//쿠키는 배열로 반환된다.
if (cookies == null) {
return null;
}
//배열을 스트림으로 바꿔줌
return Arrays.stream(cookies)
.filter(cookie -> cookie.getName().equals(cookName))
.findAny()
.orElse(null);
}
3. 세션 만료
/**
* 세션 만료
*/
public void expire(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
if (sessionCookie != null) {
sessionStore.remove(sessionCookie.getValue());
}
}
Test 생성해서 세션 적용해보기
그런데 httpServletResponse 는 인터페이스 이기때문에 구현체가 있지만 애매하다. (톰캣이 별도로 제공함)
이러한 경우에 스프링이 제공해주는 'MockHttpServletResponse'를 사용할 수 있다.
MockHttpServletResponse response = new MockHttpServletResponse();
최종코드
class SessionManagerTest {
SessionManager sessionManager = new SessionManager();
@Test
void sessionTest() {
MockHttpServletResponse response = new MockHttpServletResponse();
//세션 생성 (서버->클라이언트)
Member member = new Member();
sessionManager.createsSession(member,response );
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(response.getCookies()); //mySessionId = adkfjaewok393r...
//session 조회
Object result = sessionManager.getSession(request);
Assertions.assertThat(result).isEqualTo(member);
//세션만료
sessionManager.expire(request);
Object expired = sessionManager.getSession(request);
Assertions.assertThat(expired).isNull();
}
}
sessionManager.createsSession(member,response );
: 서버에서 세션을 만들고, 쿠키를 만들어서 응답에 담아둔 것.
즉, 서버에서 웹 브라우저에 응답이 나간 상황으로 가정할 수 있음
request.setCookies(response.getCookies());
: 웹브라우저에서 서버로 쿠키를 전송하는 것(응답에서 받은 쿠키를 가지고 요청에 쿠키를 만들어서 넣음)
안에 담긴 값은 mySessionId = adkfjaewok393r... 과 같은 예시 들 수 있음.
MockHttpServletRequest request = new MockHttpServletRequest();
:요청에 응답 쿠키가 저장되었는지 확인
여기부터 웹브라우저의 요청 (클라이언트 -> 서버) 으로 이해 가능.
실제 세션 적용해보기
LoginController
@PostMapping("login") //로그인 폼 보여줌
public String loginV2(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) {
if (bindingResult.hasErrors()) {
return "login/loginForm";
}
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
if (loginMember == null) { //회원을 못찾거나, 아이디 패스워드가 틀린 경우
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
return "login/loginForm";
}
//로그인 성공처리
//세션 관리자를 통해 세션을 생성하고, 회원데이터 보관
sessionManager.createsSession(loginMember, response);
return "redirect:/";
}
@PostMapping("/logout")
public String logoutV2(HttpServletRequest request) {
sessionManager.expire(request);
return "redirect:/";
}
HomeController
@GetMapping("/")
public String homeLoginV2(HttpServletRequest request, Model model) {
//세션 관리자에 저장된 회원 정보 조회
Member member = (Member) sessionManager.getSession(request);
//로그인
if (member == null) {
return "home";
}
model.addAttribute("member", member);
return "loginHome"; //로그인 사용자 전용 홈
}
로그아웃해도 세션아이디를 확인할 수 있지만,
실제 세션 저장소에는 삭제되었기 때문에
저 아이디는 노출되어도 상관없다.
그러나 프로젝트 마다 세션 개념을 직접 개발하는 것은 불편하므로,
서블릿은 세션 개념을 지원한다.
서블릿이 공식적으로 지원하는 세션에 대해 알아보기.
2022.10.08 - [SRPING] - [Spring] 로그인구현6_서블릿HTTP 세션, 스프링이 제공하는 SessionAttribute
Reference : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의
웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있
www.inflearn.com
강의 듣고 내용 정리중
'이론학습 > SRPING' 카테고리의 다른 글
[Spring] 로그인구현7_세션 정보와 타임아웃 설정 (1) | 2022.10.08 |
---|---|
[Spring] 로그인구현6_서블릿HTTP 세션, 스프링이 제공하는 SessionAttribute (0) | 2022.10.08 |
[Spring] 로그인구현4_세션 사용하는 이유 (0) | 2022.10.07 |
[Spring] 로그인구현3_쿠키 활용 시 발생하는 문제 (1) | 2022.10.07 |
[Spring] 로그인구현2_쿠키 활용 (0) | 2022.10.07 |