🔒 Security
JWT
세션 인증 방식을 사용하는 게 개인적으로 안전하다고 생각하지만 AWS 프리티어 서버를 사용해야 하기 때문에 서버의 부담을 줄이고자 JWT를 사용했다.
ArgumentResolver
로그인된 멤버의 아이디를 가져오기 위해서는 HttpServeletRequest에 담긴 토큰이나 SecurityContext에서 memberId를 가져오는 보일러 플레이트 코드가 생긴다. 이를 없애기 위해 ArgumentResolver를 사용해 @MemberId 애너테이션으로 memberId를 가져오도록 구현했다.
🎈 Redis
인기 검색어
인기 검색어는 Redis의 SortedSet을 사용해서 구현했다. 상품을 검색할 때 해당 상품이 1개 이상 존재한다면 SortedSet에서 검색 키워드의 score를 1만큼 올려준다. 그리고 인기 검색어 정보를 요청하면 SortedSet의 index 0부터 4까지 순서대로 score와 함께 응답으로 내보낸다.
이렇게 구현하면 데이터가 계속 쌓이게 된다. 그래서 @Scheduler 애너테이션을 사용해, 20분에 한 번씩 상위 5개 검색 키워드의 score를 5, 4, 3, 2, 1로 바꿔주고 나머지는 모두 지워줬다.
Redis vs Memcached
Redis에는 인기 검색어를 구현하는데 편리했던 SortedSet과 같은 다양한 자료구조가 있으며 참고할 수 있는 자료가 많다. 또한 성능도 큰 차이가 나지 않았다. 이러한 이유로 Memcached가 아닌 Redis를 사용하게 되었다.
요청 캐싱
RedisCacheManager와 @Cacheable을 사용해 요청을 캐싱했다. 처음에는 JSON 형식으로 캐싱을 시도했는데 Value를 역직렬화할 때 ClassCastException이 발생했다. 이는 직접 만들어준 제네릭 클래스를 Serializer가 알지 못해서였다. 그래서 일단 Java Serialization을 사용했다.
Java Serialization은 3가지 문제점이 있다.
- JSON에 비해 용량이 크다.
- 클래스에 각각 implements Serializable을 붙여야 한다.
- 제일 큰 문제로 클래스나 필드의 이름이 바뀌게 되면 에러를 발생시킨다.
따라서 Custom Serializer를 구현해 개선할 필요가 있다.
🔧 개선이 필요한 부분
- 요청 캐시 Custom Serializer를 구현해 Java Serialization에서 JSON 직렬화로 변경
- JWT Refresh Token 검증 및 재발급 Filter에서 서비스 로직으로 변경
- 지금은 모든 요청에 Refresh Token이 있는지 확인하고 있음
- 세션 인증 방식을 사용하거나 OAuth 2.0을 사용해 보안 강화
- 더 다양한 케이스로 테스트 코드 작성