-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #128 from H-Hive/feature/user
feat: Refresh Token 추가
- Loading branch information
Showing
17 changed files
with
330 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
src/main/java/com/HHive/hhive/domain/user/dto/RefreshTokenDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.HHive.hhive.domain.user.dto; | ||
|
||
import lombok.Data; | ||
|
||
@Data | ||
public class RefreshTokenDTO { | ||
|
||
String refreshToken; | ||
} |
39 changes: 39 additions & 0 deletions
39
src/main/java/com/HHive/hhive/domain/user/entity/Token.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.HHive.hhive.domain.user.entity; | ||
|
||
import jakarta.persistence.*; | ||
import lombok.*; | ||
|
||
@Entity | ||
@Table(name = "tokens") | ||
@Data | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Builder | ||
@Getter | ||
public class Token { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column | ||
private String refreshToken; | ||
|
||
@Column | ||
private boolean expired; | ||
|
||
@Column | ||
private boolean revoked; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "user_id") | ||
private User user; | ||
|
||
public void setExpired(boolean expired) { | ||
this.expired = expired; | ||
} | ||
|
||
public void setRevoked(boolean revoked) { | ||
this.revoked = revoked; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/HHive/hhive/domain/user/repository/TokenRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.HHive.hhive.domain.user.repository; | ||
|
||
import com.HHive.hhive.domain.user.entity.Token; | ||
import com.HHive.hhive.domain.user.entity.User; | ||
import com.HHive.hhive.global.exception.common.ErrorCode; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Modifying; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public interface TokenRepository extends JpaRepository<Token, Long> { | ||
|
||
List<Token> findByUser(User user); | ||
|
||
|
||
Token findByRefreshToken(String token); | ||
|
||
@Modifying | ||
@Transactional | ||
@Query("update Token t set t.expired = true, t.revoked = true where t.refreshToken = :token") | ||
void setExpiredAndRevoked(String token); | ||
} |
88 changes: 88 additions & 0 deletions
88
src/main/java/com/HHive/hhive/domain/user/service/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.HHive.hhive.domain.user.service; | ||
|
||
import com.HHive.hhive.domain.user.entity.Token; | ||
import com.HHive.hhive.domain.user.entity.User; | ||
import com.HHive.hhive.domain.user.repository.TokenRepository; | ||
import com.HHive.hhive.domain.user.repository.UserRepository; | ||
import com.HHive.hhive.global.exception.jwt.ExpiredRefreshTokenException; | ||
import com.HHive.hhive.global.exception.jwt.RefreshTokenNotFoundException; | ||
import com.HHive.hhive.global.exception.jwt.RevokedRefreshTokenException; | ||
import com.HHive.hhive.global.exception.user.UserNotFoundException; | ||
import com.HHive.hhive.global.jwt.JwtUtil; | ||
import io.jsonwebtoken.ExpiredJwtException; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class AuthService { | ||
|
||
private final TokenRepository tokenRepository; | ||
private final UserRepository userRepository; | ||
private final JwtUtil jwtUtil; | ||
|
||
@Autowired | ||
public AuthService(TokenRepository tokenRepository, UserRepository userRepository, JwtUtil jwtUtil) { | ||
this.tokenRepository = tokenRepository; | ||
this.userRepository = userRepository; | ||
this.jwtUtil = jwtUtil; | ||
} | ||
|
||
@Transactional | ||
public String createRefreshToken(Long userId) { | ||
|
||
// DB에서 User 객체를 조회 | ||
User user = userRepository.findById(userId) | ||
.orElseThrow(UserNotFoundException::new); | ||
|
||
// 토큰 만료시간 7일 | ||
long TOKEN_VALIDITY = 7 * 24 * 60 * 60 * 1000L; | ||
|
||
// JwtUtil 클래스의 메서드를 호출하여 리프레시 토큰을 생성 | ||
String refreshToken = jwtUtil.createToken(user.getUsername(), TOKEN_VALIDITY); | ||
|
||
Token tokenEntity = Token.builder() | ||
.refreshToken(refreshToken) | ||
.user(user) | ||
.expired(false) | ||
.revoked(false) | ||
.build(); | ||
|
||
tokenRepository.save(tokenEntity); | ||
|
||
return "Bearer " + refreshToken; | ||
} | ||
|
||
@Transactional | ||
public String createAccessTokenWithRefreshToken(String refreshToken) { | ||
|
||
System.out.println(refreshToken); | ||
|
||
// 데이터베이스에서 리프레시 토큰 조회 | ||
Token tokenEntity = tokenRepository.findByRefreshToken(refreshToken); | ||
|
||
if (tokenEntity == null) { | ||
throw new RefreshTokenNotFoundException(); | ||
} | ||
|
||
try { | ||
// 리프레시 토큰을 검증 | ||
jwtUtil.validationToken(refreshToken); | ||
|
||
// 리프레시 토큰이 사용 중지되었다면 예외를 발생 | ||
if (tokenEntity.isRevoked()) { | ||
throw new RevokedRefreshTokenException(); | ||
} | ||
|
||
// 액세스 토큰의 유효시간을 1시간으로 설정 | ||
long TOKEN_VALIDITY = 60 * 60 * 1000L; | ||
|
||
// 새로운 액세스 토큰을 생성하고 반환 | ||
return jwtUtil.createToken(tokenEntity.getUser().getUsername(), TOKEN_VALIDITY); | ||
|
||
} catch (ExpiredJwtException e) { | ||
// 리프레시 토큰이 만료되었다면 예외를 발생 | ||
throw new ExpiredRefreshTokenException(); | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/main/java/com/HHive/hhive/domain/user/service/LogoutService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.HHive.hhive.domain.user.service; | ||
|
||
import com.HHive.hhive.domain.user.entity.Token; | ||
import com.HHive.hhive.domain.user.repository.TokenRepository; | ||
import jakarta.persistence.EntityManager; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.web.authentication.logout.LogoutHandler; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class LogoutService implements LogoutHandler { | ||
|
||
private final TokenRepository tokenRepository; | ||
private final EntityManager entityManager; | ||
|
||
public LogoutService(TokenRepository tokenRepository, EntityManager entityManager) { | ||
this.tokenRepository = tokenRepository; | ||
this.entityManager = entityManager; | ||
} | ||
|
||
@Override | ||
@Transactional | ||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { | ||
|
||
final String authHeader = request.getHeader("Refresh-Token"); | ||
final String refreshToken; | ||
|
||
if (authHeader == null || !authHeader.startsWith("Bearer ")) { | ||
return; | ||
} | ||
|
||
refreshToken = authHeader.substring(7); | ||
|
||
Token storedToken = tokenRepository.findByRefreshToken(refreshToken); | ||
|
||
if (storedToken != null) { | ||
storedToken.setExpired(true); | ||
storedToken.setRevoked(true); | ||
|
||
tokenRepository.setExpiredAndRevoked(refreshToken); | ||
} | ||
} | ||
} |
Oops, something went wrong.