diff --git a/backend/sportsmatch/src/main/java/com/sportsmatch/auth/JwtAuthFilter.java b/backend/sportsmatch/src/main/java/com/sportsmatch/auth/JwtAuthFilter.java index e1c8a3fa..19e7dcd0 100644 --- a/backend/sportsmatch/src/main/java/com/sportsmatch/auth/JwtAuthFilter.java +++ b/backend/sportsmatch/src/main/java/com/sportsmatch/auth/JwtAuthFilter.java @@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; + import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -38,8 +39,16 @@ protected void doFilterInternal( return; } - final String jwt = authHeader.substring(7); - final String userEmail = jwtService.extractUserName(jwt); + final String jwt; + final String userEmail; + + try { + jwt = authHeader.substring(7); + userEmail = jwtService.extractUserName(jwt); + } catch (Exception e) { + filterChain.doFilter(request, response); + return; + } if (isUserAuthenticated(userEmail)) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); diff --git a/backend/sportsmatch/src/main/java/com/sportsmatch/auth/SecurityConfig.java b/backend/sportsmatch/src/main/java/com/sportsmatch/auth/SecurityConfig.java index 570b9883..83b0b2fe 100644 --- a/backend/sportsmatch/src/main/java/com/sportsmatch/auth/SecurityConfig.java +++ b/backend/sportsmatch/src/main/java/com/sportsmatch/auth/SecurityConfig.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -11,6 +12,7 @@ import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.web.cors.CorsConfiguration; @@ -44,7 +46,9 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http.csrf(AbstractHttpConfigurer::disable) + http + .exceptionHandling((exception) -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .csrf(AbstractHttpConfigurer::disable) .headers(h -> h.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .authorizeHttpRequests( r -> r.requestMatchers(WHITE_LIST_URL).permitAll().anyRequest().authenticated()) diff --git a/backend/sportsmatch/src/main/java/com/sportsmatch/controllers/AuthController.java b/backend/sportsmatch/src/main/java/com/sportsmatch/controllers/AuthController.java index a5163bef..b0b29a87 100644 --- a/backend/sportsmatch/src/main/java/com/sportsmatch/controllers/AuthController.java +++ b/backend/sportsmatch/src/main/java/com/sportsmatch/controllers/AuthController.java @@ -58,7 +58,7 @@ public ResponseEntity getUserMainPage() { try { return ResponseEntity.ok().body(userService.getMyRank()); } catch (ResponseStatusException e) { - return ResponseEntity.badRequest().body(e.getStatusCode()); + return new ResponseEntity<>(e.getMessage(), e.getStatusCode()); } } } diff --git a/backend/sportsmatch/src/test/java/com/sportsmatch/controllers/PlaceControllerTest.java b/backend/sportsmatch/src/test/java/com/sportsmatch/controllers/PlaceControllerTest.java index 0bd7f75f..71de20d2 100644 --- a/backend/sportsmatch/src/test/java/com/sportsmatch/controllers/PlaceControllerTest.java +++ b/backend/sportsmatch/src/test/java/com/sportsmatch/controllers/PlaceControllerTest.java @@ -70,8 +70,8 @@ void addNewPlaceShouldReturn403NotAuthenticatedUser() throws Exception { mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/places/add") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(placeDTO))) - // Verify that the response status is 403 Forbidden - .andExpect(MockMvcResultMatchers.status().isForbidden()); + // Verify that the response status is 401 Forbidden + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); } @Test diff --git a/frontend/sportsmatch-app/src/components/Navbar.tsx b/frontend/sportsmatch-app/src/components/Navbar.tsx index ecde4a1f..3e53154d 100644 --- a/frontend/sportsmatch-app/src/components/Navbar.tsx +++ b/frontend/sportsmatch-app/src/components/Navbar.tsx @@ -19,7 +19,7 @@ function Navbar() { setLoggedIn(true) } catch (error) { const code = (error as ApiError).status - if (code == 401) { + if (code === 401) { localStorage.removeItem('token') setLoggedIn(false) } diff --git a/frontend/sportsmatch-app/src/components/PrivateRoute.tsx b/frontend/sportsmatch-app/src/components/PrivateRoute.tsx index 6f1e1b6b..9a12b389 100644 --- a/frontend/sportsmatch-app/src/components/PrivateRoute.tsx +++ b/frontend/sportsmatch-app/src/components/PrivateRoute.tsx @@ -1,9 +1,36 @@ +import { useState, useEffect } from 'react' import { Navigate, Outlet } from 'react-router-dom' +import { OpenAPI, ExSecuredEndpointService, ApiError } from '../generated/api' const PrivateRoute = () => { const requestedUrl = window.location.pathname + const [isAuthorized, setAuthorized] = useState(true) - if (localStorage.getItem('token')) { + useEffect(() => { + if (!localStorage.getItem('token')) { + setAuthorized(false) + } + }, []) + + useEffect(() => { + const init = async () => { + if (localStorage.getItem('token')) { + OpenAPI.TOKEN = localStorage.getItem('token')! + try { + await ExSecuredEndpointService.getUserMainPage() + } catch (error) { + const code = (error as ApiError).status + if (code === 401) { + localStorage.removeItem('token') + setAuthorized(false) + } + } + } + } + init() + }, []) + + if (isAuthorized) { return } else { return