[Spring] Spring Security + JWT 로그인 구현 해보기 - 4 (refresh token 구현)
yml 파일 수정
먼저 yml 파일에 refresh 토큰 만료시간 세팅 해준다.
app:
jwtSecret: jwtsigntutorialasdfasdfasdfasdfasdf
jwtExpirationInMs: 604800000
# 여기 리프레시 한줄 추가
jwtRefreshExpirationInMs: 86400000
payload(DTO 작성)
Request
TokenRefreshRequest.java 파일
public class TokenRefreshRequest {
@NotBlank
private String refreshToken;
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
}
Response
기존 작성해놓았던 JwtAuthenticationResponse.java
파일에
refreshToken 변수를 추가했다.
- JwtAuthenticationResponse.java
@Getter @Setter
public class JwtAuthenticationResponse {
private String accessToken;
private String refreshToken;
private String tokenType = "Bearer";
public JwtAuthenticationResponse(String accessToken, String refreshToken) {
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}
}
그리고 refreshToken을 받아올 클래스 작성
2. TokenRefreshResponse.java
@Getter @Setter
public class TokenRefreshResponse {
private String accessToken;
private String refreshToken;
private String tokenType = "Bearer";
public TokenRefreshResponse(String accessToken, String refreshToken) {
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}
}
controller 작성
기존 작성해놓았던 AuthController.java
파일에 refreshToken 로직을 추가해준다.
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RefreshTokenService refreshTokenService;
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
JwtTokenProvider tokenProvider;
# 로그인 부분에 RefreshToken 추가
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginRequest.getEmail(),
loginRequest.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = tokenProvider.generateToken(authentication);
#RefreshToken 로직 추가
RefreshToken refreshToken = refreshTokenService.createRefreshToken(authentication);
return ResponseEntity.ok(new JwtAuthenticationResponse(jwt, refreshToken.getToken()));
}
# RefreshToken api 작성
@PostMapping("/refreshtoken")
public ResponseEntity<?> refreshtoken(@Valid @RequestBody TokenRefreshRequest tokenRefreshRequest) {
String requestRefreshToken = tokenRefreshRequest.getRefreshToken();
return refreshTokenService.findByToken(requestRefreshToken)
.map(refreshTokenService::verifyExpiration)
.map(RefreshToken::getUser)
.map(user -> {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
user.getEmail(), user.getPassword()
)
);
String token = tokenProvider.generateToken(authentication);
return ResponseEntity.ok(new TokenRefreshResponse(token, requestRefreshToken));
})
.orElseThrow(() -> new TokenRefreshException(requestRefreshToken, "Refresh token is not in database!"));
}
}
아래에서
Refresh Token 모델을 작성하고,
Jwt Refresh Token Service 작성할것이다.
Create Refresh Token Service
model 작성
- 먼저 리프레시 토큰 모델을 만들자.
RefreshToken.java
@Getter @Setter
@Entity(name = "refreshtoken")
public class RefreshToken {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
@Column(nullable = false, unique = true)
private String token;
@Column(nullable = false)
private Instant expiryDate;
}
repository 작성
- 리프레시 토큰 레포지토리를 생성한다.
RefreshTokenRepository.java
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
@Override
Optional<RefreshToken> findById(Long id);
Optional<RefreshToken> findByToken(String token);
int deleteByUser(User user);
}
service 작성
- 그 다음 리프레시 토큰 서비스를 생성
RefreshTokenService.java
@Service
public class RefreshTokenService {
@Value("${app.jwtRefreshExpirationInMs}")
private Long refreshTokenDurationMs;
@Autowired
private RefreshTokenRepository refreshTokenRepository;
@Autowired
private UserRepository userRepository;
public Optional<RefreshToken> findByToken(String token) {
return refreshTokenRepository.findByToken(token);
}
public RefreshToken createRefreshToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal)authentication.getPrincipal();
RefreshToken refreshToken = new RefreshToken();
refreshToken.setUser(userRepository.findById(userPrincipal.getId()).get());
refreshToken.setExpiryDate(Instant.now().plusMillis(refreshTokenDurationMs));
refreshToken.setToken(UUID.randomUUID().toString());
refreshToken = refreshTokenRepository.save(refreshToken);
return refreshToken;
}
public RefreshToken verifyExpiration(RefreshToken token) {
if (token.getExpiryDate().compareTo(Instant.now()) < 0) {
refreshTokenRepository.delete(token);
throw new TokenRefreshException(token.getToken(), "Refresh token was expired. Please make a new signin request");
}
return token;
}
@Transactional
public int deleteByUserId(Long userId) {
return refreshTokenRepository.deleteByUser(userRepository.findById(userId).get());
}
}
예외처리 Exception 작성
RefreshToken.java
@Getter @Setter
@Entity(name = "refreshtoken")
public class RefreshToken {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
@Column(nullable = false, unique = true)
private String token;
@Column(nullable = false)
private Instant expiryDate;
}
RefreshTokenRepository.java
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
@Override
Optional<RefreshToken> findById(Long id);
Optional<RefreshToken> findByToken(String token);
int deleteByUser(User user);
}
RefreshTokenService.java
@Service
public class RefreshTokenService {
@Value("${app.jwtRefreshExpirationInMs}")
private Long refreshTokenDurationMs;
@Autowired
private RefreshTokenRepository refreshTokenRepository;
@Autowired
private UserRepository userRepository;
public Optional<RefreshToken> findByToken(String token) {
return refreshTokenRepository.findByToken(token);
}
public RefreshToken createRefreshToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal)authentication.getPrincipal();
RefreshToken refreshToken = new RefreshToken();
refreshToken.setUser(userRepository.findById(userPrincipal.getId()).get());
refreshToken.setExpiryDate(Instant.now().plusMillis(refreshTokenDurationMs));
refreshToken.setToken(UUID.randomUUID().toString());
refreshToken = refreshTokenRepository.save(refreshToken);
return refreshToken;
}
public RefreshToken verifyExpiration(RefreshToken token) {
if (token.getExpiryDate().compareTo(Instant.now()) < 0) {
refreshTokenRepository.delete(token);
throw new TokenRefreshException(token.getToken(), "Refresh token was expired. Please make a new signin request");
}
return token;
}
@Transactional
public int deleteByUserId(Long userId) {
return refreshTokenRepository.deleteByUser(userRepository.findById(userId).get());
}
}
TokenRefreshException.java
@ResponseStatus(HttpStatus.FORBIDDEN)
@Getter
@Setter
public class TokenRefreshException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TokenRefreshException(String token, String message) {
super(String.format("Failed for [%s]: %s", token, message));
}
}
Author And Source
이 문제에 관하여([Spring] Spring Security + JWT 로그인 구현 해보기 - 4 (refresh token 구현)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@modsiw/Spring-Spring-Security-JWT-로그인-구현-해보기-4-refresh-token-구현저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)