diff --git a/backend/src/main/java/org/juniortown/backend/config/SecurityConfig.java b/backend/src/main/java/org/juniortown/backend/config/SecurityConfig.java index 3196033..2d201af 100644 --- a/backend/src/main/java/org/juniortown/backend/config/SecurityConfig.java +++ b/backend/src/main/java/org/juniortown/backend/config/SecurityConfig.java @@ -28,17 +28,37 @@ public class SecurityConfig { private final AuthenticationConfiguration authenticationConfiguration; private final JWTUtil jwtUtil; - //AuthenticationManager Bean 등록 + /**** + * Provides the `AuthenticationManager` bean for authentication operations. + * + * @param configuration the authentication configuration used to obtain the manager + * @return the configured `AuthenticationManager` instance + * @throws Exception if the authentication manager cannot be retrieved + */ @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { return configuration.getAuthenticationManager(); } + /**** + * Provides a BCryptPasswordEncoder bean for password hashing. + * + * @return a BCryptPasswordEncoder instance + */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } + /**** + * Configures the application's security filter chain, including CORS, CSRF, authentication, authorization, and custom filters. + * + * Sets up CORS to allow requests from "http://localhost:3000" with all methods and headers, enables credential support, and exposes the "Authorization" header. Disables CSRF protection, form login, and HTTP Basic authentication. Defines authorization rules to permit access to login, signup, and root endpoints, restrict "/admin" to users with the "ADMIN" role, and require authentication for all other endpoints. Registers a custom login filter for handling authentication at "/api/auth/login" and a JWT filter for validating tokens. Configures session management to be stateless. + * + * @param http the HttpSecurity to configure + * @return the configured SecurityFilterChain + * @throws Exception if an error occurs during configuration + */ @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http diff --git a/backend/src/main/java/org/juniortown/backend/config/WebMvcConfig.java b/backend/src/main/java/org/juniortown/backend/config/WebMvcConfig.java index 0b1abf0..1bd80c2 100644 --- a/backend/src/main/java/org/juniortown/backend/config/WebMvcConfig.java +++ b/backend/src/main/java/org/juniortown/backend/config/WebMvcConfig.java @@ -4,6 +4,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; public class WebMvcConfig implements WebMvcConfigurer { + /**** + * Configures CORS mappings to allow requests from "http://localhost:3000" for all URL paths. + * + * @param registry the CORS registry to which the mapping is added + */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") diff --git a/backend/src/main/java/org/juniortown/backend/controller/ExceptionController.java b/backend/src/main/java/org/juniortown/backend/controller/ExceptionController.java index 9574ea2..36940e8 100644 --- a/backend/src/main/java/org/juniortown/backend/controller/ExceptionController.java +++ b/backend/src/main/java/org/juniortown/backend/controller/ExceptionController.java @@ -22,6 +22,14 @@ @Slf4j @RestControllerAdvice public class ExceptionController { + /** + * Handles validation errors for method arguments and returns a structured error response. + * + * Returns an error response with HTTP 400 status, including details about each invalid field and its validation message. + * + * @param e the exception containing validation errors for method arguments + * @return an ErrorResponse with code "400", a generic bad request message, and validation error details + */ @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ErrorResponse invalidRequestHandler(MethodArgumentNotValidException e) { @@ -41,7 +49,12 @@ public ErrorResponse invalidRequestHandler(MethodArgumentNotValidException e) { return response; } - //@ResponseStatus(HttpStatus.NOT_FOUND) + /** + * Handles {@link CustomException} by returning a structured error response with the exception's status code and message. + * + * @param e the custom exception to handle + * @return a {@link ResponseEntity} containing the error response and the appropriate HTTP status code + */ @ExceptionHandler(CustomException.class) public ResponseEntity customException(CustomException e) { int statusCode = e.getStatusCode(); @@ -57,6 +70,11 @@ public ResponseEntity customException(CustomException e) { return response; } + /** + * Handles uncaught exceptions and returns a standardized 500 Internal Server Error response. + * + * @return a ResponseEntity containing an ErrorResponse with error code "500" and a generic server error message + */ @ExceptionHandler(Exception.class) public ResponseEntity exceptionHandler(Exception e) { log.error("Exception: ", e); diff --git a/backend/src/main/java/org/juniortown/backend/response/ErrorResponse.java b/backend/src/main/java/org/juniortown/backend/response/ErrorResponse.java index ef6f65b..cefd857 100644 --- a/backend/src/main/java/org/juniortown/backend/response/ErrorResponse.java +++ b/backend/src/main/java/org/juniortown/backend/response/ErrorResponse.java @@ -27,12 +27,26 @@ public class ErrorResponse { private final String code; private final String message; private final Map> validation = new HashMap<>(); + /** + * Constructs an ErrorResponse with the specified status code and error message. + * + * @param code the status code representing the error type + * @param message a descriptive error message + */ @Builder public ErrorResponse(String code, String message) { this.code = code; this.message = message; } + /** + * Adds a validation error message for a specific field. + * + * If the field already has validation messages, the new message is appended to the list; otherwise, a new list is created for the field. + * + * @param fieldName the name of the field with a validation error + * @param errorMessage the validation error message to add + */ public void addValidation(String fieldName, String errorMessage) { this.validation.computeIfAbsent(fieldName, key -> new ArrayList<>()) .add(errorMessage); diff --git a/backend/src/main/java/org/juniortown/backend/user/controller/AuthController.java b/backend/src/main/java/org/juniortown/backend/user/controller/AuthController.java index 8f05449..6336de4 100644 --- a/backend/src/main/java/org/juniortown/backend/user/controller/AuthController.java +++ b/backend/src/main/java/org/juniortown/backend/user/controller/AuthController.java @@ -20,12 +20,25 @@ @RequiredArgsConstructor public class AuthController { private final AuthService authService; + /** + * Handles user registration requests. + * + * Accepts a JSON payload containing user sign-up information, processes the registration, and responds with HTTP 201 Created upon success. + * + * @param signUpDTO the user registration data + * @return HTTP 201 Created with no response body if registration is successful + */ @PostMapping("/auth/signup") public ResponseEntity signup(@Valid @RequestBody SignUpDTO signUpDTO) { authService.signUp(signUpDTO); return ResponseEntity.status(HttpStatus.CREATED).build(); } + /** + * Handles a test POST request to verify JWT authentication. + * + * This endpoint can be used to confirm that JWT-based authentication is functioning correctly. + */ @PostMapping("/auth/jwt/test") public void test() { log.info("test"); diff --git a/backend/src/main/java/org/juniortown/backend/user/dto/CustomUserDetails.java b/backend/src/main/java/org/juniortown/backend/user/dto/CustomUserDetails.java index f03da4d..9b2e5b6 100644 --- a/backend/src/main/java/org/juniortown/backend/user/dto/CustomUserDetails.java +++ b/backend/src/main/java/org/juniortown/backend/user/dto/CustomUserDetails.java @@ -12,6 +12,11 @@ @RequiredArgsConstructor public class CustomUserDetails implements UserDetails { private final User user; + /**** + * Returns the authorities granted to the user. + * + * @return a collection containing a single authority representing the user's role + */ @Override public Collection getAuthorities() { Collection collection = new ArrayList<>(); @@ -25,11 +30,21 @@ public String getAuthority() { return collection; } + /** + * Returns the password of the user. + * + * @return the user's password + */ @Override public String getPassword() { return user.getPassword(); } + /**** + * Returns the user's email address to be used as the username for authentication. + * + * @return the user's email + */ @Override public String getUsername() { return user.getEmail(); diff --git a/backend/src/main/java/org/juniortown/backend/user/dto/LoginDTO.java b/backend/src/main/java/org/juniortown/backend/user/dto/LoginDTO.java index 1da1457..b4779f1 100644 --- a/backend/src/main/java/org/juniortown/backend/user/dto/LoginDTO.java +++ b/backend/src/main/java/org/juniortown/backend/user/dto/LoginDTO.java @@ -17,6 +17,12 @@ public class LoginDTO { @NotBlank(message = "비밀번호를 입력해주세요.") //@Size(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.") private String password; + /** + * Constructs a LoginDTO with the specified email and password. + * + * @param email the user's email address + * @param password the user's password + */ @Builder public LoginDTO(String email, String password) { this.email = email; diff --git a/backend/src/main/java/org/juniortown/backend/user/entity/User.java b/backend/src/main/java/org/juniortown/backend/user/entity/User.java index 009a33c..f347f97 100644 --- a/backend/src/main/java/org/juniortown/backend/user/entity/User.java +++ b/backend/src/main/java/org/juniortown/backend/user/entity/User.java @@ -29,6 +29,14 @@ public class User { private LocalDateTime createdAt; private String role; + /** + * Constructs a new User with the specified name, email, password, and role, setting the creation time to the current date and time. + * + * @param name the user's name + * @param email the user's email address + * @param password the user's password + * @param role the user's role + */ @Builder public User(String name, String email, String password, String role) { this.name = name; diff --git a/backend/src/main/java/org/juniortown/backend/user/exception/AlreadyExistsEmailException.java b/backend/src/main/java/org/juniortown/backend/user/exception/AlreadyExistsEmailException.java index b14082f..5015448 100644 --- a/backend/src/main/java/org/juniortown/backend/user/exception/AlreadyExistsEmailException.java +++ b/backend/src/main/java/org/juniortown/backend/user/exception/AlreadyExistsEmailException.java @@ -4,6 +4,9 @@ public class AlreadyExistsEmailException extends CustomException { public static String MESSAGE = "이미 가입된 이메일입니다."; + /**** + * Constructs an exception indicating that the email address is already registered. + */ public AlreadyExistsEmailException() { super(MESSAGE); } diff --git a/backend/src/main/java/org/juniortown/backend/user/exception/InvalidSignInformation.java b/backend/src/main/java/org/juniortown/backend/user/exception/InvalidSignInformation.java index 4892e17..e2519ed 100644 --- a/backend/src/main/java/org/juniortown/backend/user/exception/InvalidSignInformation.java +++ b/backend/src/main/java/org/juniortown/backend/user/exception/InvalidSignInformation.java @@ -5,6 +5,9 @@ public class InvalidSignInformation extends CustomException { private static final String MESSAGE = "아이디/비밀번호가 올바르지 않습니다."; + /**** + * Constructs an InvalidSignInformation exception with a predefined message indicating incorrect username or password. + */ public InvalidSignInformation() { super(MESSAGE); } diff --git a/backend/src/main/java/org/juniortown/backend/user/jwt/JWTFilter.java b/backend/src/main/java/org/juniortown/backend/user/jwt/JWTFilter.java index 971c96e..f529eb8 100644 --- a/backend/src/main/java/org/juniortown/backend/user/jwt/JWTFilter.java +++ b/backend/src/main/java/org/juniortown/backend/user/jwt/JWTFilter.java @@ -19,6 +19,17 @@ @Slf4j public class JWTFilter extends OncePerRequestFilter { private final JWTUtil jwtUtil; + /** + * Processes incoming HTTP requests to authenticate users based on JWT tokens. + * + * If a valid, non-expired JWT token is present in the "Authorization" header, sets the authentication in the security context for the request. Otherwise, continues the filter chain without authentication. + * + * @param request the HTTP request + * @param response the HTTP response + * @param filterChain the filter chain to continue processing + * @throws ServletException if an error occurs during filtering + * @throws IOException if an I/O error occurs during filtering + */ @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { diff --git a/backend/src/main/java/org/juniortown/backend/user/jwt/JWTUtil.java b/backend/src/main/java/org/juniortown/backend/user/jwt/JWTUtil.java index 989a341..dd272ab 100644 --- a/backend/src/main/java/org/juniortown/backend/user/jwt/JWTUtil.java +++ b/backend/src/main/java/org/juniortown/backend/user/jwt/JWTUtil.java @@ -16,22 +16,53 @@ public class JWTUtil { private final SecretKey secretKey; + /** + * Constructs a JWTUtil instance with a secret key for signing and verifying JWT tokens. + * + * @param secret the secret string used to generate the signing key + */ public JWTUtil(@Value("${spring.jwt.secret}")String secret) { secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); } + /** + * Extracts the "email" claim from a JWT token. + * + * @param token the JWT token string + * @return the email address contained in the token's "email" claim + */ public String getUsername(String token) { return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("email", String.class); } + /** + * Extracts the "role" claim from a JWT token after verifying its signature. + * + * @param token the JWT token string + * @return the value of the "role" claim in the token payload + */ public String getRole(String token) { return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("role", String.class); } + /** + * Determines whether the provided JWT token is expired. + * + * @param token the JWT token to check + * @return true if the token's expiration date is before the current time; false otherwise + */ public Boolean isExpired(String token) { return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().getExpiration().before(new Date()); } + /**** + * Creates a signed JWT token containing the specified email and role claims, with a set expiration time. + * + * @param email the email to include as the "email" claim + * @param role the role to include as the "role" claim + * @param expiredMs the token's validity duration in milliseconds from the current time + * @return a compact JWT string signed with the configured secret key + */ public String createJwt(String email, String role, Long expiredMs) { return Jwts.builder() diff --git a/backend/src/main/java/org/juniortown/backend/user/jwt/LoginFilter.java b/backend/src/main/java/org/juniortown/backend/user/jwt/LoginFilter.java index 522b072..4f47be6 100644 --- a/backend/src/main/java/org/juniortown/backend/user/jwt/LoginFilter.java +++ b/backend/src/main/java/org/juniortown/backend/user/jwt/LoginFilter.java @@ -32,6 +32,16 @@ public class LoginFilter extends UsernamePasswordAuthenticationFilter { private final JWTUtil jwtUtil; + /** + * Attempts to authenticate a user by reading login credentials from the HTTP request body. + * + * Parses the request body as JSON to extract the user's email and password, then delegates authentication to the authentication manager. + * + * @param request the HTTP request containing login credentials in JSON format + * @param response the HTTP response + * @return the authenticated Authentication object if credentials are valid + * @throws AuthenticationException if authentication fails or if the request body cannot be parsed as valid JSON + */ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { @@ -44,7 +54,11 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ } } - //로그인 성공시 실행하는 메소드 (여기서 JWT를 발급하면 됨) + /** + * Handles actions upon successful user authentication, including JWT token issuance. + * + * Generates a JWT token valid for 24 hours using the authenticated user's username and role, adds it to the response header, and writes a JSON login success message to the response body with HTTP status 200. + */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) { CustomUserDetails customUserDetails = (CustomUserDetails)authentication.getPrincipal(); @@ -74,7 +88,11 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR } } - //로그인 실패시 실행하는 메소드 + /** + * Handles actions to perform when user authentication fails during login. + * + * Sets the HTTP response status to 401 (Unauthorized) and writes a JSON-formatted failure message to the response body. + */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) { log.error("Login failed: {}", failed.getMessage()); diff --git a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepository.java b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepository.java index 3205a3b..0b4b42b 100644 --- a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepository.java +++ b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepository.java @@ -7,9 +7,28 @@ import org.springframework.data.repository.CrudRepository; public interface UserRepository extends JpaRepository, UserRepositoryCustom { - Optional findByEmailAndPassword(String email, String password); + /**** + * Retrieves a user matching the specified email and password. + * + * @param email the user's email address + * @param password the user's password + * @return an Optional containing the user if found, or empty if no match exists + */ +Optional findByEmailAndPassword(String email, String password); - Optional findByEmail(String email); + /**** + * Retrieves a user by their email address. + * + * @param email the email address to search for + * @return an Optional containing the user if found, or empty if no user exists with the specified email + */ +Optional findByEmail(String email); - Boolean existsByEmail(String email); + /**** + * Checks if a user exists with the specified email address. + * + * @param email the email address to check for existence + * @return true if a user with the given email exists, false otherwise + */ +Boolean existsByEmail(String email); } diff --git a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryCustom.java b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryCustom.java index d3876c5..ae34427 100644 --- a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryCustom.java +++ b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryCustom.java @@ -5,5 +5,10 @@ import org.juniortown.backend.user.entity.User; public interface UserRepositoryCustom { - List getUsers(); + /**** + * Retrieves a list of all User entities. + * + * @return a list containing User objects + */ +List getUsers(); } diff --git a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryImpl.java b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryImpl.java index 53317c9..c99462c 100644 --- a/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryImpl.java +++ b/backend/src/main/java/org/juniortown/backend/user/repository/UserRepositoryImpl.java @@ -11,6 +11,11 @@ @RequiredArgsConstructor public class UserRepositoryImpl implements UserRepositoryCustom{ private final JPAQueryFactory jpaQueryFactory; + /**** + * Retrieves a list of users. + * + * @return a list of users, or null if not implemented + */ @Override public List getUsers() { return null; diff --git a/backend/src/main/java/org/juniortown/backend/user/response/LoginResultDTO.java b/backend/src/main/java/org/juniortown/backend/user/response/LoginResultDTO.java index 817f6a7..0c44ae6 100644 --- a/backend/src/main/java/org/juniortown/backend/user/response/LoginResultDTO.java +++ b/backend/src/main/java/org/juniortown/backend/user/response/LoginResultDTO.java @@ -9,6 +9,11 @@ @NoArgsConstructor public class LoginResultDTO { private String message; + /** + * Constructs a LoginResultDTO with the specified login result message. + * + * @param message the message describing the result of a login attempt + */ @Builder public LoginResultDTO(String message) { this.message = message; diff --git a/backend/src/main/java/org/juniortown/backend/user/service/AuthService.java b/backend/src/main/java/org/juniortown/backend/user/service/AuthService.java index e19c0bc..d7aefda 100644 --- a/backend/src/main/java/org/juniortown/backend/user/service/AuthService.java +++ b/backend/src/main/java/org/juniortown/backend/user/service/AuthService.java @@ -19,6 +19,14 @@ public class AuthService { private final BCryptPasswordEncoder encoder; + /** + * Registers a new user with the provided sign-up information. + * + * If the email is already registered, throws an {@link AlreadyExistsEmailException}. + * + * @param signUpDTO the data transfer object containing user registration details + * @throws AlreadyExistsEmailException if the email is already in use + */ public void signUp(SignUpDTO signUpDTO) { Boolean isExist = userRepository.existsByEmail(signUpDTO.getEmail()); if (isExist) { diff --git a/backend/src/main/java/org/juniortown/backend/user/service/CustomUserDetailsService.java b/backend/src/main/java/org/juniortown/backend/user/service/CustomUserDetailsService.java index ddc208e..523efa5 100644 --- a/backend/src/main/java/org/juniortown/backend/user/service/CustomUserDetailsService.java +++ b/backend/src/main/java/org/juniortown/backend/user/service/CustomUserDetailsService.java @@ -16,6 +16,12 @@ @RequiredArgsConstructor public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; + /** + * Loads user details for authentication based on the provided email address. + * + * @param email the email address of the user to load + * @return a {@link CustomUserDetails} object if a user with the given email exists, or {@code null} if not found + */ @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional userData = userRepository.findByEmail(email); diff --git a/frontend/src/pages/components/Layout/Footer.js b/frontend/src/pages/components/Layout/Footer.js index 653b1cd..8e36fc1 100644 --- a/frontend/src/pages/components/Layout/Footer.js +++ b/frontend/src/pages/components/Layout/Footer.js @@ -1,5 +1,10 @@ import React from 'react'; +/** + * Renders the site footer with copyright information and links to the privacy policy and terms of service. + * + * The current year is displayed dynamically. + */ export default function Footer() { return (