Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- ㅒ
- 코드로배우는스프링웹프로젝트
- 스프링 시큐리티
- GIT
- 선형대수
- 자바편
- 이터레이터
- 처음 만나는 AI 수학 with Python
- network configuration
- iterator
- 티스토리 쿠키 삭제
- 서버설정
- 처음 만나는 AI수학 with Python
- resttemplate
- 리눅스
- d
- 자료구조와 함께 배우는 알고리즘 입문
- 구멍가게코딩단
- 페이징
- 네트워크 설정
- baeldung
- 코드로배우는스프링부트웹프로젝트
- 자료구조와함께배우는알고리즘입문
- 알파회계
- 목록처리
- /etc/network/interfaces
- 스프링부트핵심가이드
- Kernighan의 C언어 프로그래밍
- 데비안
- 친절한SQL튜닝
Archives
- Today
- Total
bright jazz music
blog33 : 쿠키를 통한 인증 및 검증 본문
지난 번 포스팅에서는 회원이 로그인을 하면 토큰이 발급되고, 인증이 필요한 페이지로 이동하려 할 때 DB에서 해당 토큰을 검증하고, 이동한 후에는 해당 회원의 primary id를 출력해 주는 과정을 다루었다.
//AuthController.java
@PostMapping("/auth/login")
public SessionResponse login(@RequestBody Login login){
String accessToken = authService.signin(login);
return new SessionResponse(accessToken);
}
### auth.http
POST http://localhost:8080/auth/login
Content-Type: application/json
{
"email" : "catnails@gmail.com",
"password" : "1234"
}
---------
이번 포스팅에서는 쿠키를 통해서 인증 및 검증하는 내용을 다룬다. 저번 포스팅처럼 헤더에 토큰을 넣어주는 방식도 사용하기는 하지만 쿠키를 사용한 인증 방식을 훨씬 더 일반적으로 사용된다.
위에서 보듯이 현재는 json으로 응답을 반환받고 있다. 그러나 이제부터는 쿠키를 사용하여 인증을 유지해야 하기 때문에 header에 쿠키 값을 넣은 응답을 받아야 한다.
1. AuthController 수정
//AuthController.java
package com.endofma.blog.controller;
import com.endofma.blog.request.Login;
import com.endofma.blog.response.SessionResponse;
import com.endofma.blog.service.AuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {
//생성자를 통한 주입
//private final UserRepository userRepository;
//로그인 및 인증 절차를 서비스에 위임
private final AuthService authService;
//AuthController.java
@PostMapping("/auth/login")
public ResponseEntity<Object> login(@RequestBody Login login){
// public SessionResponse login(@RequestBody Login login){
String accessToken = authService.signin(login);
// return new SessionResponse(accessToken);
//json이 아닌 헤더에 쿠키를 담은 값을 반환받아야 한다.
//스프링 5.0이전에는 HttpServletResponse 에 넣어주는 것이 예전 방식이었다. 여기서는 ResponseCookie를 사용한다.
ResponseCookie cookie = ResponseCookie.from("SESSION", accessToken) //key값은 SESSION으로 사용하는 것이 일반적
.domain("localhost") //로컬환경에서는 localhost, 개발에서는 dev.catnails.com 운영에서는 catnail.com 등. application.yml에 환경설증 후 구동 시 설정값을 넣어 구분해줄 수도 있다.
.path("/")
.httpOnly(true)
.secure(false) //https사용 X
.maxAge(Duration.ofDays(30)) //로그인 유지시간이나 다름없다. 기본 파라미터는 초단위다. 일반적으로는 30일을 사용한다.
.sameSite("Strict")
.build();
//쿠키 자체를 리턴하지 않는다. ResponseEntity를 사용하여 거기에 쿠키를 담아 리턴한다.
log.info(">>>>> cookie={}", cookie.toString());
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.build();
}
}
요청 테스트
### auth.http
POST http://localhost:8080/auth/login
Content-Type: application/json
{
"email" : "catnails@gmail.com",
"password" : "1234"
}
결과
응답 헤더에 Set-Cookie가 있는 것을 확인할 수 있다.
2023-02-16 22:17:19.252 INFO 17808 --- [nio-8080-exec-1] c.e.blog.controller.AuthController : >>>>> cookie=SESSION=578f914d-0517-4e16-8c6b-9454ade04d1e; Path=/; Domain=localhost; Max-Age=2592000; Expires=Sat, 18 Mar 2023 13:17:19 GMT; HttpOnly; SameSite=Strict
//로그 역시 마찬가지
2. 인증 페이지 요청
쿠키 값을 응답받을 것을 확인할 수 있다.
브라우저라면 쿠키 값을 자동으로 쿠키를 저장하여 페이지를 이동하겠지만, 여기서는 브라우저를 사용하지 않으므로 직접 쿠키 값을 넣어서 요청해야 한다.
### 인증페이지 요청
GET http://localhost:8080/foo
Content-Type: application/json
Cookie: SESSION=578f914d-0517-4e16-8c6b-9454ade04d1e
당연히 실패한다. 왜냐하면 이제 Authroization을 사용하지 않고 Cookie를 사용하기 때문이다. 따라서 AuthResolver를 수정해 준다.
3. AuthResolver(=ArgumentResolver 수정)
//AuthResolver.java
package com.endofma.blog.config;
import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.domain.Session;
import com.endofma.blog.exception.Unauthorized;
import com.endofma.blog.repository.SessionRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {
//주입
private final SessionRepository sessionRepository;
@Override
public boolean supportsParameter(MethodParameter parameter) {
//컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//실제로 해당 DTO에 값을 세팅해준다.
// String accessToken = webRequest.getHeader("Authorization"); //헤더의 값으로 확인해준다.
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest == null) { //getNativeRequest는 nullable이다
log.error("servletRequest null");
throw new Unauthorized();
}
Cookie[] cookies = servletRequest.getCookies(); //배열로 받는다.
if (cookies.length == 0) {
log.error("쿠키가 없음");
throw new Unauthorized();
}
String accessToken = cookies[0].getValue();
Session session = sessionRepository.findByAccessToken(accessToken)
.orElseThrow(Unauthorized::new);
// return new UserSession(1L);
return new UserSession(session.getUser().getId()); //컨트롤러로 넘겨준다.
}
}
고쳤으면 서버 재기동.
4. 서버 재기동 후 쿠키 재발급
재기동했으니 쿠키를 다시 발급 받아야 한다.
### auth.http
POST http://localhost:8080/auth/login
Content-Type: application/json
{
"email" : "catnails@gmail.com",
"password" : "1234"
}
POST http://localhost:8080/auth/login
HTTP/1.1 200
Set-Cookie: SESSION=41ab691f-b12f-47db-9e23-c8ad891fa496; Path=/; Domain=localhost; Max-Age=2592000; Expires=Sat, 18 Mar 2023 13:39:47 GMT; HttpOnly; SameSite=Strict
Content-Length: 0
Date: Thu, 16 Feb 2023 13:39:47 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 200; Time: 451ms (451 ms); Content length: 0 bytes (0 B)
Cookies are preserved between requests:
> D:\personal\blog\.idea\httpRequests\http-client.cookies
5. 인증페이지 요청
로그인 시 발급받은 쿠키 값을 적어주는 것에 유의
### 인증페이지 요청
GET http://localhost:8080/foo
Content-Type: application/json
Cookie: SESSION=41ab691f-b12f-47db-9e23-c8ad891fa496
잘못된 쿠키를 적고 요청을 보내면 아래와 같은 응답이 반환된다.
### 인증페이지 요청
GET http://localhost:8080/foo
Content-Type: application/json
Cookie: SESSION=41ab691f-b12f-47db-9e23-c8ad891fa496--other
'Projects > blog' 카테고리의 다른 글
blog36 : JWT를 이용한 인증 - application.yml 커스텀 설정값 만들기 (0) | 2023.02.22 |
---|---|
blog 35 : JWT를 이용한 인증 - 만들어보자 (0) | 2023.02.19 |
blog32 : 데이터베이스를 통한 토큰 검증 (0) | 2023.02.16 |
blog 31 : 세션 토큰 발급기능 추가 2 (0) | 2023.02.15 |
blog 31 : 세션 토큰 발급기능 추가 1 (0) | 2023.02.15 |
Comments