로그인 후 사용자 정보를 다른 페이지까지 유지해야 할 때,
JWT, Cookie, Session 등의 방법이 있으며, 이번 포스팅에서는 Session에 대해 다루려고 한다.
저번 포스팅에서 UserContext를 이용해서 사용자 정보를 유지하는 방법에 대해 작성했다.
UserProvider로 update한 변수가 한 페이지 이동은 연동이 되는데, 새로고침을 하거나 또 다른 페이지로 이동하면 변수가 초기화되었다...
다른 방법을 찾던 중 Session을 인증을 간단하게 하면 빠르게 구현 가능하다고 정글러분께서 추천해주셔서 세션으로 구현을 시작했다.
세션 인증 과정을 간단하게 설명하자면 아래와 같다.
(F)로그인 요청 -> (B)가입 여부 확인 후, 세션 setting -> (F)SessionStorage 에서 세팅 값 확인
사실 이게 끝이다. 추가적인 인증이나 암호화 등을 거치면 더 복잡해지겠지만, 이번 프로젝트에서는 시간 부족으로...로그인 상태를 유지하는 것을 목표로 간단하게만 구현했다.
Spring
@PostMapping(value = "/login/welcome")
public Response login(@RequestBody Login user, HttpServletRequest request, HttpSession session, Model model) {
UserEntity newUser;
newUser = ToUserEntity.toUserEntity(user);
Response code = userService.login(newUser);
log.info("{}, userLogin={}", code, user);
if (code.getCode().equals("101")){
session = request.getSession();
session.setAttribute("loginUser", newUser.getUserId());
model.addAttribute("user", newUser.getUserName());
}
return code;
}
다른 방법도 있는데 그건 이 블로그를 참고하면 좋을 것 같다 -> HttpSession은 어떻게 만들어지고 어떻게 유지될까
위 코드는 톰캣-서블릿에서 세션을 만들어서 전달해주는 방식이다. 더 간편하다고 생각해 이 방법을 선택했다.
101 코드를 통해 유효한 사용자 확인이 끝나면 메소드로 전달받은 Session에 전달하고 싶은 정보를 저장한다.
React
const sendForm = async (e) => {
e.preventDefault();
await axios.post("/login/welcome", {
'userId':userid,
'userPW':password
}, {"Content-Type": 'application/json'})
.then(function (res) {
console.log(res);
const code = res.data["code"];
if (code === "101"){
alert("login 성공");
sessionStorage.setItem("name", res.data["name"]);
sessionStorage.setItem("id", res.data["id"]);
navigate("/main");
}
else if(code === "501") {
alert("존재하지 않는 ID입니다");
}
else if(code === "502") {
alert("비밀번호가 일치하지 않습니다");
}
})
.catch(function (error) {
console.log(error);
})
}
이후 리액트에서는 전달받은 객체에 담긴 정보를 sessionStorage에 담아 갖고 다닐 수 있다.
나중에 사용할 때는 getItem("name") 처럼 사용하면 된다.
+ 수정
글을 작성하다 보니까 스프링에서 session객체를 전송하지도 않고, 리액트에서도 session을 전달받은 것처럼 보이지가 않았다. 몬가몬가...의도한 동작은 돌아가지만, 내가 구현한 방식은 세션을 이용한 전달이 아닌 것처럼 보였다.
GPT에게 수정을 받아 세션을 얕게나마 사용하는 방식으로 변경했다.
Spring
@PostMapping(value = "/login/welcome")
public ResponseEntity<Response> login(@RequestBody Login user, HttpSession session) {
UserEntity newUser;
newUser = ToUserEntity.toUserEntity(user);
Response code = userService.login(newUser);
log.info("{}, userLogin={}", code, user);
if (code.getCode().equals("101")){
session.setAttribute("loginUser", newUser.getUserId());
return ResponseEntity.ok()
.header("Set-Cookie", "JSESSIONID=" + session.getId())
.body(code);
}
return ResponseEntity.ok().body(code);
}
spring에서 세션 헤더에 세션 ID를 담아 보낸다. body에는 원래 전송했었던 객체가 들어간다.
React
await axios.post("/login/welcome", {
'userId':userid,
'userPW':password
}, {"Content-Type": 'application/json'})
.then(function (res) {
console.log(res);
const code = res.data["code"];
if (code === "101"){
alert("login 성공");
document.cookie = "JSESSIONID=" + getCookie("JSESSIONID");
sessionStorage.setItem("name", res.data["name"]);
sessionStorage.setItem("id", res.data["id"]);
navigate("/main");
}
else if(code === "501") {
alert("존재하지 않는 ID입니다");
}
else if(code === "502") {
alert("비밀번호가 일치하지 않습니다");
}
})
response 헤더에서 세션 ID를 parsing한다.
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
이 세션 ID를 가지고 서버에 전송하여 인가된 사용자임을 증명하면 된다.
GPT의 설명
이렇게 하면 클라이언트에서는 세션 ID를 받아서 쿠키에 저장하고, 이후 서버에 요청을 보낼 때마다 해당 세션 ID가 함께 전송됩니다. 서버는 이를 통해 세션을 인증하고 세션에 저장된 정보에 접근할 수 있습니다.
위 설명을 참고하여 서버와의 통신에 세션 ID를 사용하면 될 것 같다.
개선점
아직 세션을 제대로 사용하지는 않는다. 로그인한 사용자임을 증명하는 수단으로만 사용중이고, 서버와의 인증/인가 시스템에서는 활용하지 못 했기 때문에 인증/인가 시스템을 확장, 구현하려 한다.
또, 가능하다면 JWT를 사용한 방식도 구현해보고 싶다.
출처
Servlet 세션(Session)으로 상태정보 유지하기
HttpSession은 어떻게 만들어지고 어떻게 유지될까
'Web' 카테고리의 다른 글
API란? (0) | 2024.06.21 |
---|---|
[React] 동기와 비동기 / async와 await (0) | 2024.04.15 |
[Spring] CORS 설정으로 오류 해결 (0) | 2024.04.11 |
[Spring+React] 리액트에서 보낸 json 스프링에서 받기 (0) | 2024.04.06 |