로그인 정보를 클라이언트에서 받아와 처리하는 소스코드다.
실무에서 자주 쓰지 않았기 때문에, 복기할 겸 정리함
AccountController.java
@PostMapping("/api/account/login")
public ResponseEntity Login(@RequestBody Map<String, String> params, HttpServletResponse res) {
Member member = memberRepository.findByEmailAndPassword(params.get("email"), params.get("password"));
if (member != null) {
JwtService jwtService = new JwtServiceImpl();
int id = member.getId();
String token = jwtService.getToken("id", id);
Cookie cookie = new Cookie("token", token);
cookie.setHttpOnly(true); // front에서 접근 못함
cookie.setPath("/"); // 모든 경로에 유효함
res.addCookie(cookie);
// return ResponseEntity.ok().build();
return new ResponseEntity<>(id, HttpStatus.OK);
}
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
@PostMapping : 클라이언트에서 요청한 Post방식의 url과 동일하게 설정
public : 접근 제어자로, Spring에서는 @Controller나 @RestController에 선언된 메서드들은 외부 요청이 들어오기 때문에 public으로 선언해야만 작동한다.(해당 controller는 @RestController임)
ResponseEntity : 서버에서 클라이언트로 보내는 응답을 커스터마이징 가능 / return 값에 선언돼있는 것처럼 상태 코드 같은 상세내용 설정 가능(본문, 상태 코드, 헤더 설정 등)
@RequestBody : HTTP 요청 본문(body)에 포함된 데이터를 자가 객체로 변환해주는 역할이다.
클라이언트가 서버로 데이터를 보낼 때, JSON,XML,텍스트 등 어떠한 형태로 보내도 서버에서 자바 객체로 변환해 줌
주로 POST나 PUT 요청에서 사용
@PostMapping("/user")
public String createUser(@RequestBody User user) {
// 클라이언트에서 보낸 JSON 데이터를 User 객체로 변환
return "Received user: " + user.getName() + ", Age: " + user.getAge();
}
➕ 주로 Map 형식과 자주 사용되는 이유?
동적으로 변하는 키-값 쌍의 데이터를 처리하기 쉬워서다.
클라이언트에서 어떤 필드가 올지 모른다거나, 데이터 구조가 너무 복잡하다던지 필드가 여러 개여도 매번 새로운 클래스 생성 없이 Map으로 처리 가능
HttpServletResponse : 서버에서 클라이언트(브라우저 등)로 보내는 HTTP 응답을 조작할 수 있게 해주는 객체임 (주로 쿠키, 리다이렉트, 파일 다운로드 등 구체적 조작)
‼️ResponseEntity랑 HttpServletResponse 예제 비교
먼저 ResponseEntity
@PostMapping("/api/login")
public ResponseEntity<String> login() {
return ResponseEntity
.status(HttpStatus.OK)
.header("Custom-Header", "value")
.body("로그인 성공!");
}
상태 코드, 헤더, 본문까지 설정 가능 / JSON 반환이나 메세지 응답에 많이 사용
HttpServletResponse
@PostMapping("/api/login")
public ResponseEntity<Integer> login(HttpServletResponse res) {
Cookie cookie = new Cookie("token", "abc.def.ghi");
cookie.setHttpOnly(true);
cookie.setPath("/");
res.addCookie(cookie);
return ResponseEntity.ok(1);
}
쿠키를 직접 조작해야 해서 res.addCookie() 사용
이런 작업은 ResponseEntity로는 못 함
🧐 왜 JWT + 쿠키를 같이 쓰는가? 세션(sessionStorage)도 있는데?
JWT만 사용하게 됐을 때,
- 로그인 시 서버가 JWT(서명된 토큰)를 생성해서 클라이언트에 전달함
- 클라이언트는 이후 요청마다 이 JWT를 Authorization 헤더에 실어 보냄
Authorization: Bearer <token>
근데, 이렇게 되면
클라이언트가 매번 직접 헤더에 넣어줘야 하기 때문에 프론트에서 번거롭고
XSS공격에 취약할 수 있다.(localStorage에 저장하면 js로 접근 가능)
그래서 쿠키에 JWT를 넣는 방법이 등장
- JWT를 HttpOnly 쿠키에 저장하면, 자바스크립트에서 접근할 수 없어서 보안강화
- 브라우저가 요청할 때마다 자동으로 쿠키 전송 -> 개발자가 헤더 관리할 필요 X
Cookie cookie = new Cookie("token", jwtToken);
cookie.setHttpOnly(true);
res.addCookie(cookie);
그럼, Cookie 말고 sessionStorage/localStorage 써도 되는 거 아닌가?
- 일단, cookie와 다르게 보안기능 없음(HttpOnly 같은..) 그로 인해 XSS 공격에 취약!
- 탭, 창 닫으면 삭제돼버림(Cookie는 만료시점 설정가능)
- Cookie와 다르게 수동으로 전송 필요함(Cookie는 매 요청마다 서버로 자동 전송됨)
'이것저것 공부' 카테고리의 다른 글
ESLint와 Prettier의 차이 및 특징 (0) | 2025.03.21 |
---|---|
옵셔널 체이닝(Optional Chaining) (0) | 2025.03.05 |
API 게이트웨이(API Gateway) (1) | 2025.01.16 |
자료구조 힙(Heap) 예제 및 개념 (0) | 2025.01.15 |
Swagger API 사용법 2탄 (0) | 2024.11.27 |