admin: RT 를 통한 AT 재 발급 시 IP&RT expired date time 체크 로직 추가
This commit is contained in:
parent
6a1b4fe0c5
commit
a3404947a0
|
|
@ -3,11 +3,14 @@ package com.bpgroup.poc.admin.app.jwt;
|
|||
import com.bpgroup.poc.admin.domain.admin.entity.Admin;
|
||||
import com.bpgroup.poc.admin.domain.admin.service.AdminService;
|
||||
import com.bpgroup.poc.admin.domain.admin.service.AdminTokenCreateCommand;
|
||||
import com.bpgroup.poc.admin.domain.admin.service.AdminTokenExpireCommand;
|
||||
import com.bpgroup.poc.admin.domain.admin.service.AdminTokenService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
|
|
@ -16,9 +19,30 @@ public class JwtTokenAppService {
|
|||
private final AdminService adminService;
|
||||
private final AdminTokenService adminTokenService;
|
||||
|
||||
public void save(JwtTokenRequest request) {
|
||||
public void saveNewToken(JwtTokenRequest request) {
|
||||
Admin findAdmin = adminService.find(request.getLoginId()).orElseThrow(() -> new IllegalArgumentException("Not found admin"));
|
||||
adminTokenService.expire(findAdmin.getId());
|
||||
|
||||
adminTokenService.create(
|
||||
AdminTokenCreateCommand.of(
|
||||
request.getIp(),
|
||||
request.getAccessToken(),
|
||||
request.getRefreshToken(),
|
||||
request.getExpiredRefreshToken(),
|
||||
request.getState(),
|
||||
findAdmin
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public void saveRegenerateToken(JwtTokenRequest request) {
|
||||
Admin findAdmin = adminService.find(request.getLoginId()).orElseThrow(() -> new IllegalArgumentException("Not found admin"));
|
||||
adminTokenService.expire(
|
||||
AdminTokenExpireCommand.of(
|
||||
findAdmin.getId(),
|
||||
request.getIp(),
|
||||
LocalDateTime.now()
|
||||
)
|
||||
);
|
||||
|
||||
adminTokenService.create(
|
||||
AdminTokenCreateCommand.of(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.bpgroup.poc.admin.domain;
|
||||
|
||||
public class DomainException extends RuntimeException {
|
||||
public DomainException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,12 @@ package com.bpgroup.poc.admin.domain.admin.entity;
|
|||
import com.bpgroup.poc.admin.domain.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "admin_token")
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
|
|
@ -56,7 +58,11 @@ public class AdminToken extends BaseEntity {
|
|||
return new AdminToken(ip, accessToken, refreshToken, expiredRefreshTokenDateTime, state, admin);
|
||||
}
|
||||
|
||||
public void expire(TokenState state) {
|
||||
this.state = state;
|
||||
public void expire() {
|
||||
this.state = TokenState.EXPIRED;
|
||||
}
|
||||
|
||||
public boolean isNotExpired(LocalDateTime dateTime) {
|
||||
return this.expiredRefreshTokenDateTime.isAfter(dateTime);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.bpgroup.poc.admin.domain.admin.entity;
|
|||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AdminTokenRepository extends JpaRepository<AdminToken, Long> {
|
||||
List<AdminToken> findByAdminIdAndState(Long adminId, TokenState state);
|
||||
Optional<AdminToken> findLastByAdminIdAndIpAndState(Long adminId, String ip, TokenState state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.bpgroup.poc.admin.domain.admin.service;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class AdminTokenExpireCommand {
|
||||
@NotNull
|
||||
private final Long adminId;
|
||||
@NotBlank
|
||||
private final String ip;
|
||||
@NotNull
|
||||
private final LocalDateTime dateTime;
|
||||
|
||||
public static AdminTokenExpireCommand of(
|
||||
Long adminId,
|
||||
String ip,
|
||||
LocalDateTime dateTime
|
||||
) {
|
||||
return new AdminTokenExpireCommand(adminId, ip, dateTime);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.bpgroup.poc.admin.domain.admin.service;
|
||||
|
||||
import com.bpgroup.poc.admin.domain.admin.entity.*;
|
||||
import com.bpgroup.poc.admin.domain.admin.entity.AdminToken;
|
||||
import com.bpgroup.poc.admin.domain.admin.entity.AdminTokenRepository;
|
||||
import com.bpgroup.poc.admin.domain.admin.entity.TokenState;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
|
@ -8,7 +10,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
|
@ -22,11 +24,15 @@ public class AdminTokenService {
|
|||
adminTokenRepository.save(command.toEntity());
|
||||
}
|
||||
|
||||
public void expire(@NotNull Long adminId) {
|
||||
List<AdminToken> adminTokens = adminTokenRepository.findByAdminIdAndState(adminId, TokenState.NORMAL);
|
||||
adminTokens.forEach(
|
||||
adminToken -> adminToken.expire(TokenState.EXPIRED)
|
||||
);
|
||||
public void expire(@NotNull @Valid AdminTokenExpireCommand command) {
|
||||
AdminToken findAdminToken = adminTokenRepository.findLastByAdminIdAndIpAndState(command.getAdminId(), command.getIp(), TokenState.NORMAL)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Not found token"));
|
||||
|
||||
if (findAdminToken.isNotExpired(LocalDateTime.now())) {
|
||||
throw new IllegalArgumentException("Token is expired");
|
||||
}
|
||||
|
||||
findAdminToken.expire();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
package com.bpgroup.poc.admin.security.authentication;
|
||||
|
||||
import com.bpgroup.poc.admin.app.authentication.AuthenticationResult;
|
||||
import com.bpgroup.poc.admin.app.authentication.AuthenticationAppService;
|
||||
import com.bpgroup.poc.admin.app.authentication.AuthenticationResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private final AuthenticationAppService authenticationAppService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess
|
|||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
|
||||
String username = (String) authentication.getPrincipal();
|
||||
|
||||
jwtTokenProvider.generateToken(request, response, username);
|
||||
jwtTokenProvider.generateToken(request, response, username, JwtTokenProvider.JwtTokenIssueType.GENERATE);
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.bpgroup.poc.admin.security.jwt;
|
||||
|
||||
import com.bpgroup.poc.admin.app.jwt.JwtTokenRequest;
|
||||
import com.bpgroup.poc.admin.app.jwt.JwtTokenAppService;
|
||||
import com.bpgroup.poc.admin.app.jwt.JwtTokenRequest;
|
||||
import com.bpgroup.poc.admin.domain.admin.entity.TokenState;
|
||||
import com.bpgroup.poc.admin.security.jwt.exception.JwtTokenExpiredException;
|
||||
import com.bpgroup.poc.admin.security.jwt.exception.JwtTokenInvalidException;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
|
|
@ -27,23 +29,30 @@ public class JwtTokenProvider {
|
|||
// TODO: 추후 Key 별도 관리 필요
|
||||
private static final SecretKey JWT_KEY = Keys.hmacShaKeyFor(JwtTokenConstants.KEY.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
public void generateToken(HttpServletRequest request, HttpServletResponse response, String username) {
|
||||
public enum JwtTokenIssueType {
|
||||
GENERATE, REGENERATE
|
||||
}
|
||||
|
||||
public void generateToken(HttpServletRequest request, HttpServletResponse response, String username, JwtTokenIssueType issueType) {
|
||||
Cookie accessTokenCookie = createCookieWithToken(username, JwtTokenProvider.JwtTokenType.ACCESS);
|
||||
response.addCookie(accessTokenCookie);
|
||||
|
||||
Cookie refreshTokenCookie = createCookieWithToken(username, JwtTokenProvider.JwtTokenType.REFRESH);
|
||||
response.addCookie(refreshTokenCookie);
|
||||
|
||||
jwtTokenAppService.save(
|
||||
JwtTokenRequest.of(
|
||||
JwtTokenRequest jwtTokenRequest = JwtTokenRequest.of(
|
||||
request.getRemoteAddr(),
|
||||
accessTokenCookie.getValue(),
|
||||
refreshTokenCookie.getValue(),
|
||||
LocalDateTime.now().plusSeconds(refreshTokenCookie.getMaxAge()),
|
||||
TokenState.NORMAL,
|
||||
username
|
||||
)
|
||||
);
|
||||
|
||||
switch (issueType) {
|
||||
case GENERATE -> jwtTokenAppService.saveNewToken(jwtTokenRequest);
|
||||
case REGENERATE -> jwtTokenAppService.saveRegenerateToken(jwtTokenRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public enum JwtTokenType {
|
||||
|
|
@ -65,7 +74,7 @@ public class JwtTokenProvider {
|
|||
expirationTime = JwtTokenConstants.RT_EXPIRATION_TIME;
|
||||
}
|
||||
|
||||
String token = generateToken(JwtTokenConstants.ISSUER, subject, username, expirationTime);
|
||||
String token = generateToken(subject, username, expirationTime);
|
||||
|
||||
Cookie tokenCookie = new Cookie(tokenName, token);
|
||||
tokenCookie.setHttpOnly(true);
|
||||
|
|
@ -74,9 +83,9 @@ public class JwtTokenProvider {
|
|||
return tokenCookie;
|
||||
}
|
||||
|
||||
private String generateToken(String issuer, String subject, String username, long expirationTime) {
|
||||
private String generateToken(String subject, String username, long expirationTime) {
|
||||
return Jwts.builder()
|
||||
.issuer(issuer)
|
||||
.issuer(JwtTokenConstants.ISSUER)
|
||||
.subject(subject)
|
||||
.claim("username", username) .issuedAt(new Date())
|
||||
.expiration(getExpirationDate(expirationTime))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.bpgroup.poc.admin.security.jwt;
|
||||
|
||||
import com.bpgroup.poc.admin.security.jwt.exception.JwtTokenExpiredException;
|
||||
import com.bpgroup.poc.admin.security.jwt.exception.JwtTokenInvalidException;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
|
|
@ -56,7 +58,7 @@ public class JwtTokenValidateFilter extends OncePerRequestFilter {
|
|||
Claims claims = jwtTokenProvider.getClaims(refreshToken);
|
||||
String username = claims.get("username", String.class);
|
||||
|
||||
jwtTokenProvider.generateToken(request, response, username);
|
||||
jwtTokenProvider.generateToken(request, response, username, JwtTokenProvider.JwtTokenIssueType.REGENERATE);
|
||||
|
||||
setSecurityContext(username);
|
||||
} catch (JwtTokenExpiredException e) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.bpgroup.poc.admin.security.jwt;
|
||||
package com.bpgroup.poc.admin.security.jwt.exception;
|
||||
|
||||
public class JwtTokenExpiredException extends Exception {
|
||||
public JwtTokenExpiredException() {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.bpgroup.poc.admin.security.jwt;
|
||||
package com.bpgroup.poc.admin.security.jwt.exception;
|
||||
|
||||
public class JwtTokenInvalidException extends Exception {
|
||||
public JwtTokenInvalidException() {
|
||||
Loading…
Reference in New Issue