Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nathan & jerry] 웹서버 4단계 - 쿠키를 이용한 로그인 구현 #63

Open
wants to merge 13 commits into
base: nathan-jerry
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,18 @@
- orElseGet
- Supplier로 wrapping한 값을 받는다.
- **`null`일 경우에만** 뒤의 로직이 실행된다.(lazy)

---

## Step4 : 웹서버 4단계 - 쿠키를 이용한 로그인 구현

- 302, 304 차이
- 302는 리다이렉트, 304는 Not Modified로 브라우저의 캐시를 사용하므로 절대 response body를 넣으면 안된다.
- response body가 없어도 되는 상태 코드는 302, 304, 204 등이 있다.
- [Set-Cookie] HTTP/1.1 vs. HTTP/2 : 세미콜론(;)으로 결합이 가능한지 아닌지 ... 아닌 것 같음
- [Set-Cookie] 작성 순서(cookie-name=cookie-value; 옵션들(max-age, path, domain 등등))
- [Set-Cookie] Path value default 있음 (/user/create -> /user가 기본 값)
- [Set-Cookie] Path를 set-Cookie 했을 때와 동일한 Path 값을 설정해야 정상적인 로그아웃이 가능함
- 참고 : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
- 참고2: https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request

11 changes: 11 additions & 0 deletions src/main/java/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package controller;

import java.io.IOException;
import webserver.Request;
import webserver.Response;

public interface Controller {

void process(Request request, Response response) throws IOException;

}
39 changes: 39 additions & 0 deletions src/main/java/controller/FirstController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package controller;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webserver.ControllerMapper;
import webserver.HttpMethod;
import webserver.Request;
import webserver.Response;

public class FirstController {

private static final FirstController instance = new FirstController();

private final Map<ControllerMapper, Controller> map = new ConcurrentHashMap<>();
private Logger log = LoggerFactory.getLogger(FirstController.class);

private FirstController() {
map.put(new ControllerMapper(HttpMethod.POST, "/user/create"), UserJoinController.getInstance());
map.put(new ControllerMapper(HttpMethod.GET, "/user/logout"), UserLogoutController.getInstance());
map.put(new ControllerMapper(HttpMethod.POST, "/user/login"), UserLoginController.getInstance());
Comment on lines +21 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 여기서 하나의 객체만 보관해서 로직을 처리할때 꺼내는 구조로 되기 때문에, 굳이 하부 컨트롤러들이 싱글턴일 이유가 없어 보이기도 합니다.

}

public void run(Request request, Response response) throws IOException {
Controller controller = map.get(new ControllerMapper(request.getHttpMethod(), request.getPath()));
if (controller == null) {
controller = HomeController.getInstance();
}
log.debug("call {}", controller);
controller.process(request, response);
}

public static FirstController getInstance() {
return instance;
}

}
30 changes: 30 additions & 0 deletions src/main/java/controller/HomeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package controller;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webserver.HttpStatus;
import webserver.Request;
import webserver.Response;

public class HomeController implements Controller {

private static final HomeController instance = new HomeController();

private Logger log = LoggerFactory.getLogger(HomeController.class);
private HomeController() {
}

public static HomeController getInstance() {
return instance;
}

@Override
public void process(Request request, Response response) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileReader 같은 클래스가 따로 있으면 좋을 것 같은 느낌이네요~

log.debug("path: {}", request.getPath());
response.write(body, HttpStatus.OK);
}
}
57 changes: 57 additions & 0 deletions src/main/java/controller/UserJoinController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package controller;

import db.DataBase;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.Pair;
import webserver.HttpStatus;
import webserver.Request;
import webserver.Response;

public class UserJoinController implements Controller {

private static final UserJoinController instance = new UserJoinController();

private Logger log = LoggerFactory.getLogger(UserJoinController.class);

private UserJoinController() {
}

public static UserJoinController getInstance() {
return instance;
}

@Override
public void process(Request request, Response response) throws IOException {
Map<String, String> parsedBody = request.takeParsedBody();
log.debug("POST BODY: {}", parsedBody);
User user = new User(
parsedBody.get("userId"),
parsedBody.get("password"),
parsedBody.get("name"),
parsedBody.get("email")
);
saveUser(user, response);
}

private void saveUser(User user, Response response) {
List<Pair> pairs = new ArrayList<>();
if (DataBase.validateDuplicatedId(user)) {
DataBase.addUser(user);
log.debug("SavedUser: {}", user);
pairs.add(new Pair("Location", "http://localhost:8080/index.html"));
response.write(HttpStatus.FOUND, pairs);
return;
}
log.debug("Save Fail: {}", user);
pairs.add(new Pair("Location", "http://localhost:8080/user/form.html"));
response.write(HttpStatus.FOUND, pairs);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실패해도 FOUND 군요?

}
}
50 changes: 50 additions & 0 deletions src/main/java/controller/UserLoginController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package controller;

import db.DataBase;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.Pair;
import webserver.HttpSession;
import webserver.HttpStatus;
import webserver.Request;
import webserver.Response;

public class UserLoginController implements Controller {

private static final UserLoginController instance = new UserLoginController();

private Logger log = LoggerFactory.getLogger(UserLoginController.class);

private UserLoginController() {
}

public static UserLoginController getInstance() {
return instance;
}

@Override
public void process(Request request, Response response) {
Map<String, String> parsedBody = request.takeParsedBody();
log.debug("POST BODY: {}", parsedBody);

User user = DataBase.findUserById(parsedBody.get("userId"));
List<Pair> pairs = new ArrayList<>();

if (user != null && user.getPassword().equals(parsedBody.get("password"))) {
log.debug("login 성공");
pairs.add(new Pair("Location", "http://localhost:8080/index.html"));
pairs.add(new Pair("Set-Cookie", "sessionId=" + HttpSession.makeUUID(user.getUserId()) + "; max-age=20; Path=/; HttpOnly"));
response.write(HttpStatus.FOUND, pairs);
return;
}
log.debug("login 실패");
pairs.add(new Pair("Location", "http://localhost:8080/user/login_failed.html"));
response.write(HttpStatus.FOUND, pairs);
}


}
35 changes: 35 additions & 0 deletions src/main/java/controller/UserLogoutController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package controller;

import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.Pair;
import webserver.HttpStatus;
import webserver.Request;
import webserver.Response;

public class UserLogoutController implements Controller {

private static final UserLogoutController instance = new UserLogoutController();

private Logger log = LoggerFactory.getLogger(UserLogoutController.class);

private UserLogoutController() {
}

public static UserLogoutController getInstance() {
return instance;
}

@Override
public void process(Request request, Response response) {
List<Pair> pairs = new ArrayList<>();
pairs.add(new Pair("Location", "http://localhost:8080/index.html"));
pairs.add(new Pair("Set-Cookie", "sessionId=; max-age=-1; Path=/"));
response.write(HttpStatus.FOUND, pairs);

log.debug("logout 성공");
}

}
5 changes: 2 additions & 3 deletions src/main/java/db/DataBase.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package db;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.google.common.collect.Maps;

import model.User;

public class DataBase {
private static Map<String, User> users = Maps.newHashMap();
private static Map<String, User> users = new HashMap<>();

public static void addUser(User user) {
users.put(user.getUserId(), user);
Expand Down
63 changes: 0 additions & 63 deletions src/main/java/util/HttpRequestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpRequestUtils {
private static final Logger log = LoggerFactory.getLogger(HttpRequestUtils.class);

/**
* @param queryString은 URL에서 ? 이후에 전달되는 field1=value1&field2=value2 형식임
* @return
Expand Down Expand Up @@ -53,63 +49,4 @@ static Pair getKeyValue(String keyValue, String regex) {
public static Pair parseHeader(String header) {
return getKeyValue(header, ": ");
}

public static class Pair {
private final String key;
private final String value;

Pair(String key, String value) {
this.key = key.trim();
this.value = value.trim();
}

public String getKey() {
return key;
}

public String getValue() {
return value;
}

public boolean isContentLength() {
return key.equals("Content-Length");
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}

@Override
public String toString() {
return key + ": " + value;
// return "Pair [key=" + key + ", value=" + value + "]";
}
}
}
2 changes: 0 additions & 2 deletions src/main/java/util/IOUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import util.HttpRequestUtils.Pair;

public class IOUtils {
/**
Expand Down
Loading