티스토리 뷰
이번 포스팅에서는 토큰을 발급하고, 가져오는 방법을 다르게 해보겠다. 모든 코드는 깃허브에 있으니 참고해주세요.
프론트가 좋아하는 방식
프론트가 좋아한다는 방식이 무슨 말일까 ? 기존 토큰 주고받기 방식이라고 한다면,
- 클라이언트가 로그인을 한다.
- 서버가 토큰을 발급해준다.
- 클라이언트는 이제 요청을 보낼 때 마다 토큰을 헤더에 넣어서 보낸다.
- 서버는 요청에 담겨있는 헤더를 찾아서 검사한다.
- 만족하는 응답을 한다.
정도로 되겠다. 여기서 중요하게 볼 점은 로그인 이후 요청을 보낼 때 프론트에서 직접 토큰을 헤더에 넣어주는 작업을 해야 한다. 하지만 만약 직접 헤더에 넣어주는 작업을 해주지 않아도 요청할 때 자동으로 토큰을 넣어서 보내준다면 어떨까 ? 프론트가 해야할 일이 줄어드니 좋아할 것이다.
토큰을 쿠키에 담는 방식
자동으로 토큰을 넣어준다고 했는데, 누가 어떻게 넣어줄까 ? 바로 브라우저가 해준다. 백엔드에서는 원래 방식인 토큰에다가 쿠키를 감싸서 보내면, 쿠키를 받은 브라우저는 자동으로 요청에다가 쿠키를 포함시킨다. 즉, 토큰을 쿠키에 담기만 하면 된다. 아래는 기존 로그인 서비스 로직이다.
@Transactional
public String login(MemberLoginRequestDto requestDto) {
Member member = memberRepository.findByEmail(requestDto.getEmail())
.orElseThrow(() -> new IllegalArgumentException("가입되지 않은 이메일입니다."));
if(!passwordEncoder.matches(requestDto.getPassword(), member.getPassword())) {
throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
}
return jwtTokenProvider.createAccessToken(member.getEmail(), member.getRole().name());
}
토큰을 발급하고 반환하는 것은 똑같다. 그럼 이 메서드를 사용하는 컨트롤러를 보자. 아래 컨트롤러 역시 기존 방식이다.
여기서 우리는 발급한 토큰을 클라이언트한테 그대로 주지말고 쿠키에 감싸서 보내야 한다.
@PostMapping("/login")
public String login(@RequestBody MemberLoginRequestDto requestDto) {
return memberService.login(requestDto);
}
쿠키 구현
아래와 같이 쿠키를 생성한다. 쿠키는 key와 value로 이루어져 있고, 나중에 요청에서 쿠키를 찾을 때 key를 이용해서 찾는다. key는 마음대로 정하고 value에 발급한 쿠키를 넣는다.
@PostMapping("/login")
public void login(@RequestBody MemberLoginRequestDto requestDto) {
String token = memberService.login(requestDto);
Cookie cookie = new Cookie("ACCESS_TOKEN", response.getAccessToken());
}
그리고 파라미터에 HttpServletResponse 인터페이스를 추가한다. 추가하는 이유는 아래에 나와있다.
@PostMapping("/login")
public void login(@RequestBody MemberLoginRequestDto requestDto, HttpServletResponse res) {
String token = memberService.login(requestDto);
Cookie cookie = new Cookie("ACCESS_TOKEN", response.getAccessToken());
}
그리고 다음과 같이 속성들을 설정한다.
cookie.setHttpOnly(true);
cookie.setPath("/");
res.addCookie(cookie);
setHttpOnly는 브라우저에서 쿠키에 접근 여부다. true라면 브라우저에서 쿠키에 접근하지 못하게 되고, false라면 접근이 가능하다. 사용자들이 브라우저에서 쿠키로 접근하지 못하게 true로 설정한다.
setPath는 쿠키를 특정 url로 전송할지 선택할 때 사용된다. /는 모든 url에 전송한다는 뜻이다.
addCookie는 브라우저에 우리가 만든 쿠키를 적용시킨다. res.addCookie를 함으로써 브라우저에 적용된 쿠키가 자동으로 요청에 포함될 수 있는 것이다.
최종코드는 다음과 같다.
@PostMapping("/login")
public void login(@RequestBody MemberLoginRequestDto requestDto, HttpServletResponse res) {
String token = memberService.login(requestDto);
Cookie cookie = new Cookie("ACCESS_TOKEN", response.getAccessToken());
cookie.setHttpOnly(false);
cookie.setPath("/");
res.addCookie(cookie);
}
가져오기
가져오는 방법은 간단하다. 요청에서 헤더를 찾아서 값을 반환한 것처럼 해당쿠키를 찾아서 값을 반환해주면 된다. 코드는 다음과 같다.
public String resolveAccessToken(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(Cookie c : cookies) {
if(c.getName().equals(HEADER_ACCESS_TOKEN)) {
return c.getValue();
}
}
}
else {
throw new IllegalArgumentException("쿠키가 존재하지 않습니다.");
}
return null;
}
표준 CORS 요청
표준 CORS 요청에 따르면 기본적으로 쿠키를 설정하거나 주고받을 수 없다. 그래서 수동으로 쿠키를 CORS 요청에 넣어주어야 하는데,
이 역할을 하는 것이 바로 withCredentials 옵션이다. 참고로 프론트 백엔드 둘 다 해줘야 하는 옵션이다.
백엔드
스프링 시큐리티를 쓰고 있다면 아래와 같이 설정할 수 있다.
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
만약 스프링 시큐리티를 쓰지 않는다면 아래와 같이 설정할 수 있다.
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true);
}
}
프론트
프론트에서는 axios에서 아래와 같이 설정할 수 있다.
axios
.post(www.test.com, {
test: test
},
{
withCredentials : true
})
.then()
'SpringBoot' 카테고리의 다른 글
AOP를 사용해 요청 데이터를 출력하는 로그에 파라미터 값이 찍히지 않는 현상 (0) | 2022.10.19 |
---|---|
FCM을 이용해 웹 푸시 알림 API를 구현해보자 (1) | 2022.10.09 |
특정 URL은 시큐리티 필터 적용을 제외하도록 설정해보자 (2) | 2022.10.04 |
Elastic Beanstalk으로 쉽게 서비스 배포해보기 (4) | 2022.10.03 |
AWS에서 제공하는 S3에 이미지 업로드 해보기 (2) | 2022.09.19 |
- Total
- Today
- Yesterday