1. JWT 토큰 발급 메소드 수정
public Map<String, String> getToken(String email) {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new IllegalArgumentException("User not found"));
String role = user.getUserType().toString();
Long userId = user.getUserId();
String refreshToken = Jwts.builder()
.setSubject(email)
.claim("role", role)
.claim("userId", userId)
.setExpiration(new Date(System.currentTimeMillis() + REFRESH_TOKEN_EXPIRE_TIME))
.signWith(key)
.compact();
String accessToken = Jwts.builder()
.setSubject(email)
.claim("role", role)
.claim("userId", userId)
.setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE_TIME))
.signWith(key)
.compact();
Map<String, String> tokens = new HashMap<>();
tokens.put("access_token", accessToken);
tokens.put("refresh_token", refreshToken);
return tokens;
}
accessToken과 refreshToken 발급!
2. refreshToken DB에 저장(추후에 redis에 저장할 계획)
// RefreshToken DB에 저장
public void saveRefreshToken(String email, String refreshToken) {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new IllegalArgumentException("User not found"));
User updateUser = user.toBuilder().refreshToken(refreshToken).build();
userRepository.save(updateUser);
}
toBuilder를 사용하여 객체의 불변성을 유지하며 refreshToken 값을 업데이트!
이 방식은 setter를 사용하지 않고 객체를 업데이트할 수 있는 방법이다.
⬇️⬇️ setter를 사용하지 않고 tobuilder()를 사용한 이유 ⬇️⬇️
더보기
객체의 불변성을 유지하기 위해서 setter를 사용하지 않고 toBuilder를 사용했다.
객체에 setter를 사용하면 필드 값을 언제든지 변경할 수 있기 때문에, 객체의 상태가 예기치 않게 변할 수 있다.
특히 동시성 문제나 버그를 유발할 가능성이 높아짐.
불변 객체는 한 번 생성된 후 그 상태가 변하지 않기 때문에, 더 안전하고 안정적인 코드 작성이 가능하다.
toBuilder를 사용하면 기존 객체의 상태는 그대로 유지하면서, 일부 값만 변경된 새로운 객체를 생성할 수 있다.
이렇게 하면 객체의 불변성을 보장하면서도 필요한 값을 유연하게 변경할 수 있는 장점이 있다.
3. 클라이언트에 JWT 응답(access, refresh)
return ResponseEntity.ok(jwts);
4. 클라이언트에서 토큰 처리(cookie, localStorage 사용)
//로그인 요청
const Login = async () => {
try {
const response = await api.post("/api/login", {
email,
password,
});
if (response.status===200) {
const {access_token, refresh_token} = response.data;
if(access_token&&refresh_token){
const user = saveToken(access_token); // accessToken은 localStorage에 저장
document.cookie = `refresh_token=${refresh_token}; HttpOnly`;
if (user) {
// 구독 및 초기화 작업 수행
dispatch(setUser(user));
dispatch(subscribeToSSE(user.userId, access_token));
dispatch(initAlarm(user.userId, access_token));
}
}
···
access_token은 기존에 저장한 것처럼 localStorage에 저장하고, refreshToken은 보안문제가 있을 수 있으니 쿠키에 저장한다.
-> 이거 완전 틀렸음요....고친 부분은 다시 정리해서 올릴 예정...
document.cookie = `refresh_token=${refresh_token}; HttpOnly`;
• document.cookie
document.cookie는 브라우저에서 쿠키를 설정할 수 있는 API.
이 속성을 사용하여 쿠키를 추가하거나 수정한다.
* 쿠키는 사용자의 브라우저에 저장되는 작은 데이터로, 주로 세션 유지나 인증 정보를 관리하는 데 사용
• refresh_token=${refresh_token}
저장하려는 쿠키의 이름과 값을 설정
• HttpOnly
HttpOnly 플래그는 쿠키가 클라이언트 측 JavaScript에서 접근하지 못하게 제한하는 속성
- HttpOnly가 설정된 쿠키는 오직 서버로의 HTTP(S) 요청을 통해서만 접근가능
- JavaScript 코드로는 읽거나 수정할 수 없다.
* 이 속성은 XSS(크로스 사이트 스크립팅) 공격을 방지하는 데 중요한 역할을 한다.
공격자가 악성 스크립트를 주입하더라도 JavaScript에서 refresh_token을 탈취할 수 없게 만든다.
쿠키의 보안 플래그
• HttpOnly: JavaScript에서 쿠키에 접근하지 못하게 함으로써 보안 수준을 높임.
* HttpOnly 속성을 사용하면 개발자모드에서 쿠키를 확인하지 못함
• Secure: 쿠키가 HTTPS 연결을 통해서만 전송되도록 제한 (HTTPS 사용 시 추가 추천).
• SameSite: 쿠키가 사이트 간 요청에 전송되지 않도록 제한해 CSRF 공격을 방지하는 데 도움.
5. AccessToken이 만료되었을때 재발급!
다음 포스팅에서 계속,,,,,,,to be continue
'[ STUDY ] > Spring Boot' 카테고리의 다른 글
IOC / DI / AOP (2) | 2024.11.19 |
---|---|
[ JWT를 활용한 Spring Security ] Access Token 재발급 (0) | 2024.09.25 |
[ JWT를 활용한 Spring Security ] Refresh Token?Access Token? (0) | 2024.09.20 |
[ JWT를 활용한 Spring Security ] JWT 토큰 생성 (0) | 2024.09.20 |
[ JWT를 활용한 Spring Security ] JWT토큰 인증 과정 (0) | 2024.09.20 |