- 강의
- 109강(HTTP 캐싱과 스프링부트 캐싱) ~ 112강((Spring Security v2)
캐싱
- 파라토의 법칙 : 상위 20%가 전체의 80%에 영향을 미치는 현상
- 파레토 법치과 cache 활용
- 20%의 쿼리가 사용되는 쿼리의 80% 사용됨
- Cache
- 데이터의 원래 소스보다 더 효율적으로 엑세스할 수 있는 임시 저장소
- 웹 애플리케이션에서 사용
- 1) 클라이언트측 HTTP 캐시 사용 → HTTP Cache
- 2) 서버측 Spring 캐시 사용 → Spring Cache
- HTTP Cache(클라이언트측에서 사용)
- HTTP 클라이언트의 요청에 대한 응답값 임시 저장소
- Cache Validation을 서버에 보내서 캐시 유효성 확인이 필요
- HTTP Response Header
- Cache-Control : 어떤 방식으로 유지할지 설정
- Expire : 캐시 응답 만료 시점
- X-Cache : Cache Hit 해당 요청값이 캐시로 응답
- X-Cache-Location : 해당 Cache가 어디서 저장되었는지 확인(저장소 : Disk 또는 Memory Cache)
Cache Validation
- 캐시값 유효성 검증
- 방식 1) If-Modified-Since : 캐시를 얻을 시점 이후로 변경한 사항이 있는지 검증 하는 방식
- 문제점 : 나라마다 다른 시간을 사용할 경우 문제가 발생할 수 있음
- 방식 2) E-tag : 할당된 캐시의 ID에 대해서 변경사항이 있는지 검증하는 방식
- 클라이언트가 If-Noe-Match 값(캐시 ID값) 변경 사항이 없으면 HTTP/1.1 304 Not modified 보냄
- 아쉬운 점
- 계속 동작되는 SQL문
- 큰 서버 속도 변화 X
- E-tag를 이용한 코드 실습
- 첫번째 클라이언트의 response Headers에 Etag 가져옴 → 다음 클라이어트 요청 시 If-Noe-Match 에 Etag값을 넣어서 보내면 E-tag 캐시 사용 가능
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
@Configuration
public class EtagWebConfig {
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter(){
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new ShallowEtagHeaderFilter());
filterRegistrationBean.addUrlPatterns("/api/*"); // API 패턴 설정
return filterRegistrationBean;
}
}
Spring Cache
- Spring Cache를 사용해서 같은 DB의 질의인 경우에는 RDB 질의 X
- 사용
- 캐시값 설정하기 : @Cacheable
- key = 키값, value = 메서드의 반환값(캐시값)
- key 값 : #root.methodName, #ids
- service layer에서 많이 사용
- 캐기값 초기화 : @CacheEvict
- value = 초기화할 캐시값, allEntries = true
- 종속성 추가
- // Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
- // Cache
- 캐시 사용
- Main 메서드에 @EnableCache 추가
- 캐시값 설정하기 : @Cacheable
HTTP 쿠키, 세션, 토큰
- HTTP 특징 : 무상태성(Stateless) → 사용자 인증 문제 발생
- 해결방법
- 1) 쿠키 & 세션 방식 : 서버가 사용자 정보를 가지고 있는 경우
- 2) 토큰 방식 : 클라이언트측에서 사용자 정보를 가지고 있는 경우
- 해결방법
Cookie
- 브라우저에 저장되는 작은 정보 조각
- 클라이언트에서 사용자 정보를 저장하고 있는 방식
- 보안 이슈 발생
- 쿠키 요구 화면 필요
- 다크 모드 여부, 폰트 정보 등 가벼운 정보 저장
Session
- 서버에서 사용자 정보를 저장하고 있는 방식
- 사용자 인증을 할 경우, 서버는 사용자에 대한 정보를 저장하고 사용자에 대한 Session키를 발급해줌 → 클라이언트가 세션키를 쿠키에 저장해서 사용, 사용자 관련 요청 필요 시 세션키를 서버 요청값에 포함시켜서 요청하기
- 실습 코드
- set-session API를 통해서 세션을 생성하고, 클라이언트는 세션값을 coockie에 저장해서 사용
package com.github.supercodingspring.web.controller.sample;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/api")
public class SessionTokenSampleController {
// 세션 생성
@GetMapping("/set-session")
public String setSession(HttpSession session){
session.setAttribute("user", "조인성");
session.setAttribute("gender", "남자");
session.setAttribute("job", "배우");
return "Session Set successfully";
}
@GetMapping("/set-session2")
public String setSession2(HttpSession session){
session.setAttribute("user", "송혜교");
session.setAttribute("gender", "여자");
session.setAttribute("job", "배우");
return "Session Set successfully";
}
@GetMapping("/get-session")
public String getSession(HttpSession session){
String user = (String) session.getAttribute("user");
String gender = (String) session.getAttribute("gender");
String job = (String) session.getAttribute("job");
return String.format("안녕하세요, 직업: %s 성별: %s인 %s 입니다.", job, gender, user);
}
}
JWT
- Json Web Token
- Json 포맷을 이용해서 사용자 속성을 저장하는 claim 기반의 web token 방식
- 구조
- Header
- alg : 암호화 알고리즘
- typ : JWT
- Payload
- Claim 모음의 사용자 속성(공개 claim, 비공개 claim)
- 등록 claim : sub, exp와 같은 메타 정보
- Signature
- 유효성 검증과 암호화 코드
- 알고리즘 hash값
- Header
- 사용
- implementation 'io.jsonwebtoken:jjwt:0.9.1'
- 실습 예제
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/api")
public class SessionTokenSampleController {
@GetMapping("/generate-token")
public String generateToken(HttpServletResponse httpServletResponse){
String jwt = Jwts.builder()
.setSubject("token1")
.claim("user", "조인성")
.claim("gender", "남자")
.claim("job", "배우")
.compact();
httpServletResponse.addHeader("Token", jwt);
return "JWT set Successfully";
}
@GetMapping("/generate-token2")
public String generateToken2(HttpServletResponse httpServletResponse){
String jwt = Jwts.builder()
.setSubject("token1")
.claim("user", "송혜교")
.claim("gender", "여자")
.claim("job", "배우")
.compact();
httpServletResponse.addHeader("Token", jwt);
return "JWT set Successfully";
}
@GetMapping("/show-token")
public String showToken(@RequestHeader("Token") String token){
Claims claims = Jwts.parser()
.parseClaimsJwt(token)
.getBody();
String user = (String) claims.get("user");
String gender = (String) claims.get("gender");
String job = (String) claims.get("job");
return String.format("안녕하세요, 직업: %s 성별: %s인 %s 입니다.", job, gender, user);
}
}
JWT vs Cookie&Session
- JWT
- 장점 : 상태없음, 분산 시스템 유리
- 단점 : 취약한 보안, JWT 크기 증가
- => 다양한 플랫폼 운영 가능
- 쿠키 & 세션
- 장점 : 보안 유리, 유저 관리 용이
- 단점 : 상태유지, 서버 부담 큼
- => 서버 측에서 사용자 상태 관리
'슈퍼코딩 > 주특기(JAVA)' 카테고리의 다른 글
슈퍼코딩 신입연수원 10주차 후기 (0) | 2024.06.08 |
---|---|
2024.06.07(금) 슈퍼코딩 신입연수원 10주차 Day 5 후기 - Spring Security, 보안기초 (0) | 2024.06.07 |
2024.06.05(수) 슈퍼코딩 신입연수원 10주차 Day 3 후기 - 테스팅, 서버 업무, 서블릿 컨테이너, filter, interceptor (0) | 2024.06.05 |
2024.06.04(화) 슈퍼코딩 신입연수원 10주차 Day 2 후기 - JPA, PSA (0) | 2024.06.04 |
2024.06.03(월) 슈퍼코딩 신입연수원 10주차 Day 1 후기 - 예외 처리, AOP (0) | 2024.06.03 |