api server login 구현 [2] session cookie 로그인 처리

최준호·2022년 4월 28일
0

game

목록 보기
7/14
post-thumbnail

이전 포스트에서 token을 발급 받아서 log까지 찍어봤으니 이제 api server와 front에서 어떻게 관리해야할지 생각해보았다.

Cookie에만 저장하자니 탈취, 위조가 너무 쉽고 DB에 저장하자니 access_token의 경우 유효 시간이 30분인데 30분마다 db에 저장해서 사용해야 하는건가? 라는 생각이 들었다.

그러던 중 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 김영한 강사님 강의에 로그인 처리 부분이 있는 것을 확인했고 해당 강의를 바로 학습하니 해결방법이 나왔다...(김영한 강사님은 신이야)

결국 해결 방법으로 채택한 것은 session과 cookie를 이용하는 방법인데 server side인 session에 랜덤한 id 값을 key 값으로 token들을 저장해두고 해당 key 값은 cookie로 만들어서 client에 저장시킨다.

🔨소스 수정

Controller

@RestController
@RequestMapping("/api/member")
@Slf4j
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

	...

    //로그인
    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody RequestLogin requestLogin, HttpServletRequest request, HttpServletResponse response){
        ResponseEntity<String> responseEntity = memberService.login(requestLogin, request, response);
        return ResponseEntity.status(responseEntity.getStatusCode()).contentType(MediaType.APPLICATION_JSON).body("responseEntity.getBody()");
    }
}

session을 얻기 위해 request를 받으며 cookie를 넣어주기 위해 response를 사용해야한다.

Service

@Service
@RequiredArgsConstructor
@Slf4j
public class MemberServiceImpl implements MemberService{
    private final WebClientConfig webClient;

	...
    
    @Override
    public ResponseEntity<String> login(RequestLogin requestLogin, HttpServletRequest request, HttpServletResponse response) {
        ResponseEntity<String> result = webClient.webClient().post()  //get 요청
                .uri("/login-service/game/login")    //요청 uri
                .body(Mono.just(requestLogin), RequestLogin.class)
                .retrieve()//결과 값 반환
                .toEntity(String.class)
                .block();

        //token parse
        String body = result.getBody();
        try {
            JwtToken token = new ObjectMapper().readValue(body, JwtToken.class);
            String accessToken = token.getAccess_token();
            String refreshToken = token.getRefresh_token();

            log.debug("accessToken = {}", accessToken);
            log.debug("refreshToken = {}", refreshToken);

            //request에서 session 전달 받기
            String accessTokenId = UUID.randomUUID().toString();
            String refreshTokenId = UUID.randomUUID().toString();
            HttpSession session = request.getSession(true); //true를 주면 session이 없을 때 session을 만들고 시작함
            session.setAttribute(accessTokenId, accessToken);   //session에 access_token 값을 저장
            session.setAttribute(refreshTokenId, refreshToken);   //session에 refresh_token 값을 저장 , remeber me 의 기능을 구현하고 싶다면 db에 저장

            //cookie에는 session id 값을 저장
            Cookie accessTokenCookie = new Cookie("access_token_id_cookie", accessTokenId);
            accessTokenCookie.setMaxAge(30*60);    //단위는 초 , 30분으로 지정
            accessTokenCookie.setPath("/");
            accessTokenCookie.setHttpOnly(true);    //http를 통해서만 쿠키가 보내짐
            //accessTokenCookie.setSecure(true);    //https에서만 쿠키가 보내지도록
            Cookie refreshTokenCookie = new Cookie("refresh_token_id_cookie", refreshTokenId);
            refreshTokenCookie.setHttpOnly(true);
            refreshTokenCookie.setMaxAge(7*24*60*60);    //7일
            refreshTokenCookie.setPath("/");
            Cookie memberCookie = new Cookie("user_id", requestLogin.getUserId());
            memberCookie.setHttpOnly(true);
            memberCookie.setPath("/");

            response.addCookie(accessTokenCookie);
            response.addCookie(refreshTokenCookie);
            response.addCookie(memberCookie);

        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }

        return result;
    }
}

기존의 token log를 찍던 코드에서 session을 저장하며 cookie를 생성하는 코드를 추가로 작성해주었다.

그럼 이제 로그인 했을 때

다음과 같이 쿠키들이 생성되었고 session 또한 JSESSIONID라는 이름으로 생성되어 있는 것을 확인할 수 있다.

이렇게 수정된 이유는 session의 경우 front에서 처리할 수 없고 무조건 back end에서 값을 가져와서 해당 내용을 확인하거나 수정할 수 있다. 그렇기 때문에 session을 탈취당한다 한들 access_token_id 값과 refresh_token_id 값을 함께 탈취해서 보내야하며 이 또한 session이 만료되었거나 access_token이 만료, 혹은 refresh_token이 만료되었을 경우 더 이상 필요 없는 값이 되기 때문에 이와 같이 처리했다.

아 혹시라도 api가 아닌 모놀로식으로 개발하시는 분들의 경우 session이 생성되어 질때 url 창에 ;jession=~~과 같은 데이터가 추가되는 것을 확인할 수도 있는데 해당 내용은

server.servlet.session.tracking-mode=cookie

로 yml이나 properties 파일에 추가하여 session이 cookie에만 등록되게 해주면 된다.
해당 데이터가 추가되는 이유는 화면 이동시 파라미터처럼 들고 다니기 위해 추가되어지는건데 cookie로 설정시 cookie에만 추가되기 때문에 더이상 표시되지 않는다.

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글