guest session

This commit is contained in:
2026-02-27 20:11:37 +01:00
parent ee405e78e6
commit 5529217a3a
7 changed files with 39 additions and 15 deletions

View File

@@ -22,9 +22,10 @@ public class RefreshToken {
@Column(nullable = false) @Column(nullable = false)
private LocalDateTime created; private LocalDateTime created;
@Column(name = "session_id")
private String sessionId;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "user_id", nullable = false) @JoinColumn(name = "user_id", nullable = false)
private User user; private User user;
}
}

View File

@@ -11,5 +11,5 @@ public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Inte
Optional<RefreshToken> findByUserId(Integer userId); Optional<RefreshToken> findByUserId(Integer userId);
} Optional<RefreshToken> findByUserEmail(String email);
}

View File

@@ -28,12 +28,13 @@ public class JwtTokenProvider {
this.jwtValidityInMilliseconds = jwtValidityInMilliseconds; this.jwtValidityInMilliseconds = jwtValidityInMilliseconds;
} }
public String generateToken(@NonNull User user) { public String generateToken(@NonNull User user, String sessionId) {
Map<String, Object> claims = new HashMap<>(); Map<String, Object> claims = new HashMap<>();
claims.put(AuthenticationConstants.USER_ID, user.getId()); claims.put(AuthenticationConstants.USER_ID, user.getId());
claims.put(AuthenticationConstants.USERNAME, user.getUsername()); claims.put(AuthenticationConstants.USERNAME, user.getUsername());
claims.put(AuthenticationConstants.USER_EMAIL, user.getEmail()); claims.put(AuthenticationConstants.USER_EMAIL, user.getEmail());
claims.put(AuthenticationConstants.USER_REGISTRATION_STATUS, user.getRegistrationStatus().name()); claims.put(AuthenticationConstants.USER_REGISTRATION_STATUS, user.getRegistrationStatus().name());
claims.put(AuthenticationConstants.SESSION_ID, sessionId);
claims.put(AuthenticationConstants.LAST_UPDATE, LocalDateTime.now().toString()); claims.put(AuthenticationConstants.LAST_UPDATE, LocalDateTime.now().toString());
return createToken(claims, user.getEmail()); return createToken(claims, user.getEmail());
@@ -93,5 +94,11 @@ public class JwtTokenProvider {
.signWith(secretKey, SignatureAlgorithm.HS512) .signWith(secretKey, SignatureAlgorithm.HS512)
.compact(); .compact();
} }
public String getSessionId(String token) {
Claims claims = getAllClaimsFromToken(token);
return claims.get(AuthenticationConstants.SESSION_ID, String.class);
}
} }

View File

@@ -2,6 +2,7 @@ package com.balex.rag.security.filter;
import com.balex.rag.model.constants.ApiErrorMessage; import com.balex.rag.model.constants.ApiErrorMessage;
import com.balex.rag.security.JwtTokenProvider; import com.balex.rag.security.JwtTokenProvider;
import com.balex.rag.service.impl.RefreshTokenServiceImpl;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException; import io.jsonwebtoken.SignatureException;
@@ -36,6 +37,7 @@ public class JwtRequestFilter extends OncePerRequestFilter {
private static final String REGISTER_PATH = "/auth/register"; private static final String REGISTER_PATH = "/auth/register";
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenServiceImpl refreshTokenService;
@Override @Override
protected void doFilterInternal( protected void doFilterInternal(
@@ -61,8 +63,16 @@ public class JwtRequestFilter extends OncePerRequestFilter {
Optional<String> emailOpt = Optional.ofNullable(jwtTokenProvider.getUsername(jwt)); Optional<String> emailOpt = Optional.ofNullable(jwtTokenProvider.getUsername(jwt));
Optional<String> userIdOpt = Optional.ofNullable(jwtTokenProvider.getUserId(jwt)); Optional<String> userIdOpt = Optional.ofNullable(jwtTokenProvider.getUserId(jwt));
String sessionId = jwtTokenProvider.getSessionId(jwt);
if (emailOpt.isPresent() && userIdOpt.isPresent()) { if (emailOpt.isPresent() && userIdOpt.isPresent()) {
// Check session validity
Optional<String> activeSessionId = refreshTokenService.getSessionIdByEmail(emailOpt.get());
if (activeSessionId.isEmpty() || !activeSessionId.get().equals(sessionId)) {
sendErrorResponse(response, HttpStatus.UNAUTHORIZED, "SESSION_INVALIDATED");
return;
}
if (SecurityContextHolder.getContext().getAuthentication() == null) { if (SecurityContextHolder.getContext().getAuthentication() == null) {
List<SimpleGrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority(USER_ROLE)); List<SimpleGrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority(USER_ROLE));
@@ -75,7 +85,6 @@ public class JwtRequestFilter extends OncePerRequestFilter {
} }
} }
} catch (ExpiredJwtException e) { } catch (ExpiredJwtException e) {
handleTokenExpiration(requestURI, jwt, response); handleTokenExpiration(requestURI, jwt, response);
return; return;

View File

@@ -53,7 +53,7 @@ public class AuthServiceImpl implements AuthService {
.orElseThrow(() -> new InvalidDataException(ApiErrorMessage.INVALID_USER_OR_PASSWORD.getMessage())); .orElseThrow(() -> new InvalidDataException(ApiErrorMessage.INVALID_USER_OR_PASSWORD.getMessage()));
RefreshToken refreshToken = refreshTokenService.generateOrUpdateRefreshToken(user); RefreshToken refreshToken = refreshTokenService.generateOrUpdateRefreshToken(user);
String token = jwtTokenProvider.generateToken(user); String token = jwtTokenProvider.generateToken(user, refreshToken.getSessionId());
UserProfileDTO userProfileDTO = userMapper.toUserProfileDto(user, token, refreshToken.getToken()); UserProfileDTO userProfileDTO = userMapper.toUserProfileDto(user, token, refreshToken.getToken());
userProfileDTO.setToken(token); userProfileDTO.setToken(token);
@@ -65,7 +65,7 @@ public class AuthServiceImpl implements AuthService {
RefreshToken refreshToken = refreshTokenService.validateAndRefreshToken(refreshTokenValue); RefreshToken refreshToken = refreshTokenService.validateAndRefreshToken(refreshTokenValue);
User user = refreshToken.getUser(); User user = refreshToken.getUser();
String accessToken = jwtTokenProvider.generateToken(user); String accessToken = jwtTokenProvider.generateToken(user, refreshToken.getSessionId());
return RagResponse.createSuccessfulWithNewToken( return RagResponse.createSuccessfulWithNewToken(
userMapper.toUserProfileDto(user, accessToken, refreshToken.getToken()) userMapper.toUserProfileDto(user, accessToken, refreshToken.getToken())
@@ -74,7 +74,6 @@ public class AuthServiceImpl implements AuthService {
@Override @Override
public RagResponse<UserProfileDTO> registerUser(@NotNull RegistrationUserRequest request) { public RagResponse<UserProfileDTO> registerUser(@NotNull RegistrationUserRequest request) {
accessValidator.validateNewUser( accessValidator.validateNewUser(
request.getUsername(), request.getUsername(),
request.getEmail(), request.getEmail(),
@@ -86,8 +85,8 @@ public class AuthServiceImpl implements AuthService {
newUser.setPassword(passwordEncoder.encode(request.getPassword())); newUser.setPassword(passwordEncoder.encode(request.getPassword()));
userRepository.save(newUser); userRepository.save(newUser);
RefreshToken refreshToken = refreshTokenService.generateOrUpdateRefreshToken(newUser); RefreshToken refreshToken = refreshTokenService.generateOrUpdateRefreshToken(newUser);
String token = jwtTokenProvider.generateToken(newUser); String token = jwtTokenProvider.generateToken(newUser, refreshToken.getSessionId());
UserProfileDTO userProfileDTO = userMapper.toUserProfileDto(newUser, token, refreshToken.getToken()); UserProfileDTO userProfileDTO = userMapper.toUserProfileDto(newUser, token, refreshToken.getToken());
userProfileDTO.setToken(token); userProfileDTO.setToken(token);

View File

@@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Optional;
@Slf4j @Slf4j
@Service @Service
@@ -21,10 +22,12 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
@Override @Override
public RefreshToken generateOrUpdateRefreshToken(User user) { public RefreshToken generateOrUpdateRefreshToken(User user) {
String sessionId = ApiUtils.generateUuidWithoutDash();
return refreshTokenRepository.findByUserId(user.getId()) return refreshTokenRepository.findByUserId(user.getId())
.map(refreshToken -> { .map(refreshToken -> {
refreshToken.setCreated(LocalDateTime.now()); refreshToken.setCreated(LocalDateTime.now());
refreshToken.setToken(ApiUtils.generateUuidWithoutDash()); refreshToken.setToken(ApiUtils.generateUuidWithoutDash());
refreshToken.setSessionId(sessionId);
return refreshTokenRepository.save(refreshToken); return refreshTokenRepository.save(refreshToken);
}) })
.orElseGet(() -> { .orElseGet(() -> {
@@ -32,6 +35,7 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
newToken.setUser(user); newToken.setUser(user);
newToken.setCreated(LocalDateTime.now()); newToken.setCreated(LocalDateTime.now());
newToken.setToken(ApiUtils.generateUuidWithoutDash()); newToken.setToken(ApiUtils.generateUuidWithoutDash());
newToken.setSessionId(sessionId);
return refreshTokenRepository.save(newToken); return refreshTokenRepository.save(newToken);
}); });
} }
@@ -46,5 +50,8 @@ public class RefreshTokenServiceImpl implements RefreshTokenService {
return refreshTokenRepository.save(refreshToken); return refreshTokenRepository.save(refreshToken);
} }
} public Optional<String> getSessionIdByEmail(String email) {
return refreshTokenRepository.findByUserEmail(email)
.map(RefreshToken::getSessionId);
}
}

View File

@@ -11,6 +11,7 @@ public final class AuthenticationConstants {
public static final String USER_EMAIL = "email"; public static final String USER_EMAIL = "email";
public static final String USER_REGISTRATION_STATUS = "userRegistrationStatus"; public static final String USER_REGISTRATION_STATUS = "userRegistrationStatus";
public static final String LAST_UPDATE = "lastUpdate"; public static final String LAST_UPDATE = "lastUpdate";
public static final String ACCESS_KEY_HEADER_NAME = "key"; public static final String SESSION_ID = "sessionId";
public static final String ACCESS_KEY_HEADER_NAME = "key";
} }