From a3c1f4369d77a1fbed4831ca32245a2e5477ed52 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:37:17 +0900 Subject: [PATCH 01/10] =?UTF-8?q?refact=20:=20URL=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존에 입력으로 받았던 호스트 정보를 상수로 수정하였습니다. - setRedirect** 메소드명을 changePathTo** 메소드명으로 변경하였습니다. - Login 실패시 리다이렉트할 주소도 추가하였습니다. --- src/main/java/webserver/URL.java | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/webserver/URL.java b/src/main/java/webserver/URL.java index c1592232..0ce967ca 100644 --- a/src/main/java/webserver/URL.java +++ b/src/main/java/webserver/URL.java @@ -2,31 +2,36 @@ public class URL { - private static final String SCHEME = "http://"; + private static final String BASE_PATH = "http://localhost:8080"; private static final String HOME_PAGE_PATH = "/index.html"; private static final String SINE_UP_PAGE_PATH = "/user/form.html"; - - private final String homePage; - private final String signUpPage; + private static final String LOGIN_FAILED_PAGE_PATH = "/user/login_failed.html"; private String path; + private String redirectPath; - public URL(String path, String host) { + public URL(String path) { this.path = path; - homePage = SCHEME + host + HOME_PAGE_PATH; - signUpPage = SCHEME + host + SINE_UP_PAGE_PATH; } public String getPath() { return path; } - public void setRedirectHomePage() { - path = homePage; + public String getRedirectPath() { + return redirectPath; + } + + public void changePathToHomePage() { + redirectPath = BASE_PATH + HOME_PAGE_PATH; + } + + public void changePathToSignUpPage() { + redirectPath = BASE_PATH + SINE_UP_PAGE_PATH; } - public void setRedirectSignUpPage() { - path = signUpPage; + public void changePathToLoginFailedPage() { + redirectPath = BASE_PATH + LOGIN_FAILED_PAGE_PATH; } public boolean comparePath(String targetPath) { From 445a1e6c0a9196fa4f22c6cbdc4399dc5d0f7878 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:40:35 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat=20:=20RequestLine=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - requestline 을 관리하는 클래스를 추가하였습니다. --- src/main/java/webserver/RequestLine.java | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/webserver/RequestLine.java diff --git a/src/main/java/webserver/RequestLine.java b/src/main/java/webserver/RequestLine.java new file mode 100644 index 00000000..b0ddc2da --- /dev/null +++ b/src/main/java/webserver/RequestLine.java @@ -0,0 +1,32 @@ +package webserver; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; + +public class RequestLine { + + private String methodType; + private URL url; + + public RequestLine(String methodType, String url) { + this.methodType = methodType; + this.url = makeURL(url); + } + + private URL makeURL(String url) { + String decodedUrl = URLDecoder.decode(url, StandardCharsets.UTF_8); + return new URL(decodedUrl); + } + + public boolean isGetMethodType() { + return "GET".equals(methodType); + } + + public boolean isPostMethodType() { + return "POST".equals(methodType); + } + + public URL getUrl() { + return url; + } +} From be42f2c6b789dc9893603deace6868f2c255afa6 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:44:29 +0900 Subject: [PATCH 03/10] =?UTF-8?q?refact=20:=20Request=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RequestLine 클래스를 생성함에 따라, 기존에 필드로 관리되었던 Methodtype, URL 등을 requestLine 필드에서 호출할 수 있게 하였습니다. --- src/main/java/webserver/Request.java | 29 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/webserver/Request.java b/src/main/java/webserver/Request.java index 9fa2c055..8fe093ca 100644 --- a/src/main/java/webserver/Request.java +++ b/src/main/java/webserver/Request.java @@ -4,32 +4,39 @@ public class Request { - private String methodType; - private String requestLine; + private RequestLine requestLine; + private Map headers; private String messageBody; - private URL url; - public Request(String requestLine, String messageBody, String methodType, URL url) { + public Request(RequestLine requestLine, Map headers, String messageBody) { this.requestLine = requestLine; + this.headers = headers; this.messageBody = messageBody; - this.methodType = methodType; - this.url = url; } public String getMessageBody() { return messageBody; } - public String getRequestLine() { + public RequestLine getRequestLine() { return requestLine; } - public URL getURL() { - return url; + public Map getHeaders() { + return headers; } - public String getMethodType() { - return methodType; + public boolean isGetMethodType() { + return requestLine.isGetMethodType(); } + + public boolean isPostMethodType() { + return requestLine.isPostMethodType(); + } + + public URL getUrl() { + return requestLine.getUrl(); + } + } From 2620c8d0426bebec9841ccfd71c5f28eb3c09cf1 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:45:49 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat=20:=20RequestReader=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Request 객체를 가공하는 클래스를 추가하였습니다. --- src/main/java/webserver/RequestReader.java | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/main/java/webserver/RequestReader.java diff --git a/src/main/java/webserver/RequestReader.java b/src/main/java/webserver/RequestReader.java new file mode 100644 index 00000000..91a23956 --- /dev/null +++ b/src/main/java/webserver/RequestReader.java @@ -0,0 +1,72 @@ +package webserver; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import util.IOUtils; +import util.RequestLineUtil; + +public class RequestReader { + + private static final Logger log = LoggerFactory.getLogger(RequestReader.class); + + private final BufferedReader bufferedReader; + + public RequestReader(BufferedReader bufferedReader) { + this.bufferedReader = bufferedReader; + } + + public Request getRequest() throws IOException { + RequestLine requestLine = makeRequestLine(bufferedReader); + + Map headers = makeRequestHeaders(bufferedReader); + outputLog(headers); + + String messageBody = ""; + if (requestLine.isPostMethodType()) { + messageBody = IOUtils.readData(bufferedReader, + Integer.parseInt(headers.get("Content-Length:"))); + log.debug(messageBody); + } + + return new Request(requestLine, headers, messageBody); + } + + private void outputLog(Map headers) { + // Request Headers Log + for (Entry entry : headers.entrySet()) { + log.debug("Request: {} {}", entry.getKey(), entry.getValue()); + } + } + + private RequestLine makeRequestLine(BufferedReader bufferedReader) throws IOException { + String line; + if ("".equals(line = bufferedReader.readLine()) || line == null) { + throw new IllegalArgumentException("Request.bufferedReader.readLine == null 입니다."); + } + // Request Line Log + log.debug(line); + + String url = RequestLineUtil.getURL(line); + String methodType = RequestLineUtil.getMethodType(line); + return new RequestLine(methodType, url); + } + + private Map makeRequestHeaders(BufferedReader bufferedReader) + throws IOException { + Map headers = new HashMap<>(); + String line; + while (!"".equals(line = bufferedReader.readLine())) { + if (line == null) { + throw new IllegalArgumentException("Request.bufferedReader.readLine == null 입니다."); + } + String[] splitLine = line.split(" "); + headers.put(splitLine[0], splitLine[1]); + } + return headers; + } +} From 806ec7065f599a0908bb6d82e2224c051c62a833 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:48:32 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat=20:=20UserManger=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 회원 정보를 추가, 조회, 삭제하는 클래스를 추가하였습니다. - SessionId 를 가공해서 반환하는 역할도 수행합니다. --- src/main/java/webserver/UserManager.java | 76 ++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/main/java/webserver/UserManager.java diff --git a/src/main/java/webserver/UserManager.java b/src/main/java/webserver/UserManager.java new file mode 100644 index 00000000..a7e8a505 --- /dev/null +++ b/src/main/java/webserver/UserManager.java @@ -0,0 +1,76 @@ +package webserver; + +import db.DataBase; +import db.SessionDataBase; +import java.util.Map; +import java.util.UUID; +import model.User; +import util.HttpRequestUtils; + +public class UserManager { + + private final Request request; + + public UserManager(Request request) { + this.request = request; + } + + private void save(URL url, String messageBody) { + Map userInfo = HttpRequestUtils.parseQueryString(messageBody); + User user = new User(userInfo.get("userId"), userInfo.get("password"), + userInfo.get("name"), + userInfo.get("email")); + + if (DataBase.findUserById(userInfo.get("userId")) == null) { + DataBase.addUser(user); + url.changePathToHomePage(); + } else { + url.changePathToSignUpPage(); + } + } + + private String login(URL url, String messageBody) { + Map userInfo = HttpRequestUtils.parseQueryString(messageBody); + User user = DataBase.findUserById(userInfo.get("userId")); + + if (user.getUserId().equals(userInfo.get("userId")) && user.getPassword() + .equals(userInfo.get("password"))) { + String sessionId = UUID.randomUUID().toString(); + SessionDataBase.add(sessionId, userInfo.get("userId")); + + url.changePathToHomePage(); + return sessionId; + } else { + url.changePathToLoginFailedPage(); + return ""; + } + } + + private String logout(URL url, Map headers) { + String value = headers.get("Cookie:"); + String sessionId = value.split("=")[1]; + + SessionDataBase.remove(sessionId); + url.changePathToHomePage(); + + return sessionId; + } + + public String action() { + URL url = request.getUrl(); + String messageBody = request.getMessageBody(); + + if (request.isPostMethodType() && url.comparePath("/user/create")) { + save(url, messageBody); + } + if (request.isPostMethodType() && url.comparePath("/user/login")) { + return login(url, messageBody); + } + if (request.isGetMethodType() && url.comparePath("/user/logout")) { + Map headers = request.getHeaders(); + return logout(url, headers); + } + + return ""; + } +} From f888fd952de30a319f0e1c57df613291210f3b33 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:49:08 +0900 Subject: [PATCH 06/10] =?UTF-8?q?feat=20:=20SessionDataBase=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SessionId와 해당하는 유저 아이디를 관리하는 클래스를 추가하였습니다. --- src/main/java/db/SessionDataBase.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/db/SessionDataBase.java diff --git a/src/main/java/db/SessionDataBase.java b/src/main/java/db/SessionDataBase.java new file mode 100644 index 00000000..bb8c645e --- /dev/null +++ b/src/main/java/db/SessionDataBase.java @@ -0,0 +1,22 @@ +package db; + +import com.google.common.collect.Maps; +import java.util.Map; + +public class SessionDataBase { + + private static Map sessions = Maps.newHashMap(); + + public static void add(String sessionId, String userId) { + sessions.put(sessionId, userId); + } + + public static String findBySessionId(String sessionId) { + return sessions.get(sessionId); + } + + public static void remove(String sessionId) { + sessions.remove(sessionId); + } + +} From 046f47294f1309d21393f9c799540bb49cd6ca10 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:54:16 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat=20:=20Response=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EC=BF=A0=ED=82=A4=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 유저 로그인시, 생성한 SessionId를 Response header 에 추가하는 메소드를 수정하였습니다. - 유저 로그아웃시, 생성한 SessionId의 삭제를 위해 max-age=0으로 설정하는 메소드를 추가하였습니다. --- src/main/java/webserver/Response.java | 47 ++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index 502bd5af..84b9fbac 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -8,23 +8,36 @@ public class Response { private byte[] body; private String headers; - private String requestLine; + private String sessionId; + private RequestLine requestLine; private URL url; - public Response(String requestLine, URL url) { + public Response(RequestLine requestLine, String sessionId) { this.requestLine = requestLine; - this.url = url; + this.url = requestLine.getUrl(); + this.sessionId = sessionId; } public void action() throws IOException { - if (requestLine.contains("POST") && requestLine.contains("/user/create")) { - headers = response302Header(url); - } else { - body = Files.readAllBytes(new File("./webapp" + url.getPath()).toPath()); - headers = response200Header(body.length); + if (requestLine.isPostMethodType()) { + if (url.comparePath("/user/create")) { + headers = response302Header(url); + } + if (url.comparePath("/user/login")) { + headers = response302Header(url, sessionId, true); + } + } + if (requestLine.isGetMethodType()) { + if (url.comparePath("/user/logout")) { + headers = response302Header(url, sessionId, false); + } else { + body = Files.readAllBytes(new File("./webapp" + url.getPath()).toPath()); + headers = response200Header(body.length); + } } } + private String response200Header(int lengthOfBodyContent) { StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK \r\n"); @@ -39,7 +52,23 @@ private String response302Header(URL url) { StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 302 Found \r\n"); sb.append("Content-Type: text/html;charset=utf-8\r\n"); - sb.append("Location: " + url.getPath() + "\r\n"); + sb.append("Location: " + url.getRedirectPath() + "\r\n"); + sb.append("\r\n"); + + return sb.toString(); + } + + private String response302Header(URL url, String sessionId, boolean isLogin) { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP/1.1 302 Found \r\n"); + sb.append("Content-Type: text/html;charset=utf-8\r\n"); + sb.append("Location: " + url.getRedirectPath() + "\r\n"); + + if (isLogin) { + sb.append("Set-Cookie: sessionId = " + sessionId + "; Path=/\r\n"); + } else { + sb.append("Set-Cookie: sessionId = " + sessionId + "; max-age=0; Path=/\r\n"); + } sb.append("\r\n"); return sb.toString(); From 606a131f4fed42f0c7bd51b110a025d28b1b3ca9 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:56:28 +0900 Subject: [PATCH 08/10] =?UTF-8?q?refact=20:=20RequestHandler=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User 도메인 객체를 직접 생성하고 다뤘던 것을, UserManger 클래스를 사용하는 것으로 수정하였습니다. --- src/main/java/webserver/RequestHandler.java | 95 ++------------------- 1 file changed, 5 insertions(+), 90 deletions(-) diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index 03eb5fc0..56e4a6a8 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -1,6 +1,5 @@ package webserver; -import db.DataBase; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; @@ -9,17 +8,8 @@ import java.io.OutputStream; import java.net.Socket; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import util.HttpRequestUtils; -import util.IOUtils; -import util.RequestLineUtil; public class RequestHandler extends Thread { @@ -38,39 +28,21 @@ public void run() { try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) { BufferedReader br = new BufferedReader(new InputStreamReader(in)); - Request request = makeRequest(br); + RequestReader requestReader = new RequestReader(br); + Request request = requestReader.getRequest(); - // URL init - URL url = request.getURL(); - - // user save - if (request.getMethodType().equals("POST") && url.comparePath("/user/create")) { - String messageBody = request.getMessageBody(); - userSave(messageBody, url); - } + UserManager userManager = new UserManager(request); + String sessionId = userManager.action(); // Response Message DataOutputStream dos = new DataOutputStream(out); - Response response = new Response(request.getRequestLine(), url); + Response response = new Response(request.getRequestLine(), sessionId); sendResponse(dos, response); } catch (IOException e) { log.error(e.getMessage()); } } - private void userSave(String messageBody, URL url) { - Map userInfo = HttpRequestUtils.parseQueryString(messageBody); - User user = new User(userInfo.get("userId"), userInfo.get("password"), userInfo.get("name"), - userInfo.get("email")); - - if (DataBase.findUserById(userInfo.get("userId")) == null) { - DataBase.addUser(user); - url.setRedirectHomePage(); - } else { - url.setRedirectSignUpPage(); - } - } - private void sendResponse(DataOutputStream dos, Response response) throws IOException { response.action(); @@ -82,61 +54,4 @@ private void sendResponse(DataOutputStream dos, Response response) throws IOExce dos.write(body, 0, body.length); } } - - - private Request makeRequest(BufferedReader bufferedReader) throws IOException { - String requestLine = initRequestLine(bufferedReader); - Map headers = new HashMap<>(); - - initRequestHeaders(bufferedReader, headers); - outputLog(headers, requestLine); - - URL url = initURL(requestLine, headers); - - String messageBody = ""; - String methodType = RequestLineUtil.getMethodType(requestLine); - - if (methodType.equals("POST")) { - messageBody = IOUtils.readData(bufferedReader, - Integer.parseInt(headers.get("Content-Length:"))); - log.debug(messageBody); - } - - return new Request(requestLine, messageBody, methodType, url); - } - - private void outputLog(Map headers, String requestLine) { - // Request Line Log - log.debug(requestLine); - // Request Headers Log - for (Entry entry : headers.entrySet()) { - log.debug("Request: {} {}", entry.getKey(), entry.getValue()); - } - } - - private String initRequestLine(BufferedReader bufferedReader) throws IOException { - String line; - if ("".equals(line = bufferedReader.readLine()) || line == null) { - throw new IllegalArgumentException("Request.bufferedReader.readLine == null 입니다."); - } - return line; - } - - private void initRequestHeaders(BufferedReader bufferedReader, Map headers) - throws IOException { - String line; - while (!"".equals(line = bufferedReader.readLine())) { - if (line == null) { - throw new IllegalArgumentException("Request.bufferedReader.readLine == null 입니다."); - } - String[] splitLine = line.split(" "); - headers.put(splitLine[0], splitLine[1]); - } - } - - private URL initURL(String requestLine, Map headers) { - String decodedUrl = URLDecoder.decode(requestLine, StandardCharsets.UTF_8); - String host = headers.get("Host:"); - return new URL(RequestLineUtil.getURL(decodedUrl), host); - } } From af20a76a5b038289b6d5e91a97a8c6b7336d0405 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:57:41 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat=20:=20index.html=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그아웃 기능 구현을 위해, 로그아웃 버튼의 href 경로를 수정하였습니다. --- webapp/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/index.html b/webapp/index.html index 1675898a..939884b9 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -71,7 +71,7 @@
  • 로그인
  • 회원가입
  • --> -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • @@ -145,4 +145,4 @@ - \ No newline at end of file + From 8ff76e2aabcbd9b1f45ed0fc81cc01fdc74358f6 Mon Sep 17 00:00:00 2001 From: bugpigg Date: Thu, 31 Mar 2022 15:58:31 +0900 Subject: [PATCH 10/10] =?UTF-8?q?docs=20:=20README.md=204=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 6fb23e96..79ef5b2a 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,17 @@ Java Web Server Project for CodeSquad Members 2022 - [x] POST 로 회원가입 기능이 정상적으로 동작하도록 구현 - [x] 중복아이디를 처리하기 위해서 `Map` 로 회원목록을 관리 - [x] 가입 후 페이지 이동을 위해 redirection 기능을 구현 + +## 4단계. 쿠키를 이용한 로그인 구현 +### 기능요구사항 +- [x] 회원가입한 사용자로 로그인을 할 수 있어야 한다. +- [x] “로그인” 메뉴를 클릭하면 `http://localhost:8080/user/login.html` 으로 이동해 로그인할 수 있다. +- [x] 로그인이 성공하면 index.html로 이동하고, 로그인이 실패하면 /user/login_failed.html로 이동해야 한다. + +### 프로그래밍 요구사항 +- [x] 정상적으로 로그인 되었는지 확인하려면 앞 단계에서 회원가입한 데이터를 유지해야 한다. +- [x] 앞 단계에서 회원가입할 때 생성한 User 객체를 DataBase.addUser() 메서드를 활용해 메모리에 저장한다. +- [x] 필요에 따라 Database 클래스의 메소드나 멤버변수를 수정해서 사용한다. +- [x] 아이디와 비밀번호가 같은지를 확인해서 로그인이 성공하면 응답 header의 Set-Cookie 값을 sessionId=적당한값으로 설정한다. +- [x] Set-Cookie 설정시 모든 요청에 대해 Cookie 처리가 가능하도록 Path 설정 값을 /(Path=/)로 설정한다. +- [x] 응답 header에 Set-Cookie값을 설정한 후 요청 header에 Cookie이 전달되는지 확인한다.