From 0b8356693a389c88da16a254cf89656ff253cc6a Mon Sep 17 00:00:00 2001 From: balex Date: Wed, 18 Mar 2026 21:57:34 +0100 Subject: [PATCH] hr guest --- .gitlab-ci.yml | 2 +- auth-view/src/pages/LoginPage.tsx | 47 +++++++++++++++---- .../gateway/controller/AuthController.java | 6 +++ .../gateway/security/JwtTokenProvider.java | 21 +++++++-- .../posthub/gateway/service/AuthService.java | 14 ++++++ .../src/main/resources/application.yml | 4 ++ rag-view/docker/Dockerfile | 4 ++ rag-view/src/features/constants.js | 6 +-- 8 files changed, 87 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c93a942..ad4efd3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -202,7 +202,7 @@ publish-rag-view: before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - - docker build -t $REGISTRY/rag-view:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/rag-view:latest -f rag-view/docker/Dockerfile rag-view/ + - docker build --build-arg VITE_GUEST_EMAIL=$VITE_GUEST_EMAIL --build-arg VITE_GUEST_PASSWORD=$VITE_GUEST_PASSWORD -t $REGISTRY/rag-view:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/rag-view:latest -f rag-view/docker/Dockerfile rag-view/ - docker push $REGISTRY/rag-view:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/rag-view:latest needs: [build-rag-view] diff --git a/auth-view/src/pages/LoginPage.tsx b/auth-view/src/pages/LoginPage.tsx index d1c77ea..087f363 100644 --- a/auth-view/src/pages/LoginPage.tsx +++ b/auth-view/src/pages/LoginPage.tsx @@ -15,6 +15,7 @@ export default function LoginPage() { const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); + const [showPassword, setShowPassword] = useState(false); // Handle OAuth2 callback — token & refreshToken in URL useEffect(() => { @@ -77,14 +78,25 @@ export default function LoginPage() { - setPassword(e.target.value)} - placeholder="••••••••" - className="w-full bg-gray-800 border border-gray-700 text-white rounded-lg px-4 py-2.5 text-sm placeholder-gray-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition" - /> +
+ setPassword(e.target.value)} + placeholder="••••••••" + className="w-full bg-gray-800 border border-gray-700 text-white rounded-lg px-4 py-2.5 pr-10 text-sm placeholder-gray-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition" + /> + +
{error && ( @@ -150,6 +162,25 @@ export default function LoginPage() { ); } +function EyeIcon() { + return ( + + + + + ); +} + +function EyeOffIcon() { + return ( + + + + + + ); +} + function GoogleIcon() { return ( diff --git a/gateway-service/src/main/java/com/posthub/gateway/controller/AuthController.java b/gateway-service/src/main/java/com/posthub/gateway/controller/AuthController.java index 3cea092..0db3239 100644 --- a/gateway-service/src/main/java/com/posthub/gateway/controller/AuthController.java +++ b/gateway-service/src/main/java/com/posthub/gateway/controller/AuthController.java @@ -54,6 +54,12 @@ public class AuthController { }); } + @PostMapping("/hr-guest-token") + public Mono>> hrGuestToken() { + return authService.hrGuestToken() + .map(ResponseEntity::ok); + } + private void addAuthCookie(ServerHttpResponse response, String token) { ResponseCookie cookie = ResponseCookie.from("Authorization", token) .httpOnly(true) diff --git a/gateway-service/src/main/java/com/posthub/gateway/security/JwtTokenProvider.java b/gateway-service/src/main/java/com/posthub/gateway/security/JwtTokenProvider.java index 8c71a21..591a089 100644 --- a/gateway-service/src/main/java/com/posthub/gateway/security/JwtTokenProvider.java +++ b/gateway-service/src/main/java/com/posthub/gateway/security/JwtTokenProvider.java @@ -46,12 +46,12 @@ public class JwtTokenProvider { claims.put(USER_REGISTRATION_STATUS, user.getRegistrationStatus().name()); claims.put(SESSION_ID, sessionId); claims.put(LAST_UPDATE, LocalDateTime.now().toString()); - return createToken(claims, user.getEmail()); + return createToken(claims, user.getEmail(), jwtValidityInMilliseconds); } public String refreshToken(String token) { Claims claims = getAllClaimsFromToken(token); - return createToken(claims, claims.getSubject()); + return createToken(claims, claims.getSubject(), jwtValidityInMilliseconds); } public boolean validateToken(String token) { @@ -99,13 +99,26 @@ public class JwtTokenProvider { } } - private String createToken(Map claims, String subject) { + private String createToken(Map claims, String subject, long validityMs) { return Jwts.builder() .claims(claims) .subject(subject) .issuedAt(new Date()) - .expiration(new Date(System.currentTimeMillis() + jwtValidityInMilliseconds)) + .expiration(new Date(System.currentTimeMillis() + validityMs)) .signWith(secretKey) .compact(); } + + public String generateHrGuestToken(@NonNull User user) { + Map claims = new HashMap<>(); + claims.put(USER_ID, user.getId()); + claims.put(USERNAME, user.getUsername()); + claims.put(USER_EMAIL, user.getEmail()); + claims.put(USER_ROLE, user.getRole().name()); + claims.put(USER_REGISTRATION_STATUS, user.getRegistrationStatus().name()); + claims.put(SESSION_ID, "guest"); + claims.put(LAST_UPDATE, LocalDateTime.now().toString()); + return createToken(claims, user.getEmail(), 3_600_000L); + } + } \ No newline at end of file diff --git a/gateway-service/src/main/java/com/posthub/gateway/service/AuthService.java b/gateway-service/src/main/java/com/posthub/gateway/service/AuthService.java index 091ef8e..6db969d 100644 --- a/gateway-service/src/main/java/com/posthub/gateway/service/AuthService.java +++ b/gateway-service/src/main/java/com/posthub/gateway/service/AuthService.java @@ -15,6 +15,7 @@ import com.posthub.gateway.security.JwtTokenProvider; import com.posthub.gateway.util.PasswordUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -33,6 +34,8 @@ public class AuthService { private final RefreshTokenRepository refreshTokenRepository; private final JwtTokenProvider jwtTokenProvider; private final PasswordEncoder passwordEncoder; + @Value("${hr-guest.email}") + private String hrGuestEmail; public Mono> login(LoginRequest request) { return userRepository.findByEmail(request.getEmail().toLowerCase()) @@ -104,6 +107,17 @@ public class AuthService { }); } + public Mono> hrGuestToken() { + return userRepository.findByEmail(hrGuestEmail) + .switchIfEmpty(Mono.error(new ResponseStatusException( + HttpStatus.NOT_FOUND, "HR guest user not found"))) + .map(user -> { + String accessToken = jwtTokenProvider.generateHrGuestToken(user); + UserProfileDTO dto = toUserProfileDto(user, accessToken, null); + return RagResponse.createSuccessfulWithNewToken(dto); + }); + } + private Mono> generateTokensAndBuildResponse(User user) { return refreshTokenRepository.findByUserId(user.getId()) .flatMap(existing -> { diff --git a/gateway-service/src/main/resources/application.yml b/gateway-service/src/main/resources/application.yml index b06a24e..dc4f65c 100644 --- a/gateway-service/src/main/resources/application.yml +++ b/gateway-service/src/main/resources/application.yml @@ -28,6 +28,9 @@ spring: token-uri: https://graph.facebook.com/v21.0/oauth/access_token user-info-uri: https://graph.facebook.com/v21.0/me?fields=id,name,email + # ---- Guest user (portfolio chat) ---- + hr-guest: + email: ${HR_GUEST_EMAIL:} # ---- R2DBC (reactive DB) ---- r2dbc: @@ -114,6 +117,7 @@ auth: - /actuator/** - /api/*/v3/api-docs/** - /api/*/swagger-ui/** + - /api/auth/hr-guest-token admin-paths: - /api/*/admin/** diff --git a/rag-view/docker/Dockerfile b/rag-view/docker/Dockerfile index 26d99eb..775f7a2 100644 --- a/rag-view/docker/Dockerfile +++ b/rag-view/docker/Dockerfile @@ -3,6 +3,10 @@ WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . +ARG VITE_GUEST_EMAIL +ARG VITE_GUEST_PASSWORD +ENV VITE_GUEST_EMAIL=$VITE_GUEST_EMAIL +ENV VITE_GUEST_PASSWORD=$VITE_GUEST_PASSWORD RUN npm run build FROM nginx:alpine diff --git a/rag-view/src/features/constants.js b/rag-view/src/features/constants.js index a4253a4..b5d5595 100644 --- a/rag-view/src/features/constants.js +++ b/rag-view/src/features/constants.js @@ -1,7 +1,6 @@ export const BASE_URL = `${import.meta.env.VITE_API_BASE_URL || ""}/api/rag`; export const AUTH_BASE_URL = `${import.meta.env.VITE_API_BASE_URL || ""}/api/auth`; export const METHOD_POST_QUERY = "POST"; -//export const METHOD_POST_QUERY = "POST"; export const METHOD_GET_QUERY = "GET"; export const METHOD_DELETE_QUERY = "DELETE"; export const HEADER_CONTENT_TYPE = "Content-Type"; @@ -10,11 +9,10 @@ export const JWT_REFRESH_TOKEN = "refreshToken"; export const APPLICATION_JSON = "application/json"; export const USER_NAME_UNDEFINED = "userNameUndefined"; export const USER_EMAIL_UNDEFINED = "userEmailUndefined"; -export const GUEST_EMAIL = "guest@gmail.com"; -export const GUEST_PASSWORD = "Guest123!"; +export const GUEST_EMAIL = import.meta.env.VITE_GUEST_EMAIL; +export const GUEST_PASSWORD = import.meta.env.VITE_GUEST_PASSWORD; export const ERROR_RESPONSE_NOT_OK = "Response not ok"; export const ERROR_NO_RESPONSE = "No response from server"; -export const PREFIX_AUTH = "/auth"; export const PREFIX_USERS = "/users"; export const PREFIX_CHAT = "/chat"; export const PREFIX_ENTRY = "/entry";