Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ public class UserController {

private final UserServiceImpl userService;

@GetMapping("/check-username")
@Operation(summary = "아이디 중복 체크", description = "사용 가능하면 false, 이미 사용 중이면 true 반환")
public ResponseEntity<BaseResponse<Boolean>> checkUsernameDuplicate(
@RequestParam String username
) {
boolean isDuplicate = userService.checkUsernameDuplicate(username);
return ResponseEntity.ok(BaseResponse.success("아이디 중복 체크 성공", isDuplicate));
}
Comment on lines +32 to +39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

보안 설정으로 인해 엔드포인트 접근 불가 - 수정 필요

SecurityConfig.java의 설정에서 .requestMatchers("/api/users/**").authenticated().requestMatchers(HttpMethod.GET, "/api/**").permitAll() 보다 먼저 평가됩니다. 따라서 /api/users/check-username 엔드포인트는 인증되지 않은 사용자에게 401을 반환하여, 회원가입 전 아이디 중복 체크 목적을 달성할 수 없습니다.

SecurityConfig.java에서 해당 엔드포인트를 명시적으로 허용해야 합니다:

.requestMatchers("/api/users/check-username").permitAll()  // 이 줄 추가
.requestMatchers("/api/users/signup").permitAll()
.requestMatchers("/api/users/**").authenticated()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/be/sportizebe/domain/user/controller/UserController.java`
around lines 32 - 39, The check-username GET endpoint is blocked by the current
SecurityConfig matcher ordering; update SecurityConfig so the public user
endpoints are explicitly permitted before the catch-all authenticated rule: add
a requestMatchers("/api/users/check-username").permitAll() (and ensure it
appears before requestMatchers("/api/users/**").authenticated()), keeping
existing requestMatchers("/api/users/signup").permitAll() and the HttpMethod.GET
"/api/**" permitAll rule positioned appropriately; verify the
UserController.checkUsernameDuplicate mapping remains GET
/api/users/check-username and test unauthenticated access.


@PostMapping("/signup")
@Operation(summary = "회원가입", description = "이메일과 비밀번호로 회원가입")
@Operation(summary = "회원가입", description = "아이디와 비밀번호로 회원가입")
public ResponseEntity<BaseResponse<SignUpResponse>> signUp(@RequestBody @Valid SignUpRequest request) {
SignUpResponse response = userService.signUp(request);
return ResponseEntity.status(HttpStatus.CREATED)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.be.sportizebe.domain.user.dto.request;

import com.be.sportizebe.common.enums.SportType;
import com.be.sportizebe.domain.user.entity.Gender;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

import java.util.List;

public record SignUpRequest(
@Schema(description = "사용자 아이디(이메일 형식)", example = "user@example.com")
@Schema(description = "사용자 아이디", example = "sportize_user")
@NotBlank(message = "아이디를 입력해주세요.")
@Email(message = "아이디는 이메일 형식만 지원합니다.")
String username,

@Schema(description = "비밀번호", example = "password123")
Expand All @@ -26,6 +27,9 @@ public record SignUpRequest(

@Schema(description = "전화번호", example = "010-xxxx-xxxx")
@NotBlank(message = "전화번호를 입력해주세요")
String phoneNumber
String phoneNumber,

@Schema(description = "관심 종목 목록 (선택)", example = "[\"SOCCER\", \"BASKETBALL\"]")
List<SportType> interestSports
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public record SignUpResponse(
@Schema(description = "사용자 식별자", example = "1")
Long userId,

@Schema(description = "사용자 아이디(이메일 형식)", example = "user@example.com")
@Schema(description = "사용자 아이디", example = "sportize_user")
String username,

@Schema(description = "사용자 권한", example = "USER")
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/be/sportizebe/domain/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ public class User extends BaseTimeEntity {
@Enumerated(EnumType.STRING)
private Role role;

@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "user_interest_types", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "sport_type")
@Enumerated(EnumType.STRING)
private List<SportType> interestType; // 사용자 관심 종목
@Builder.Default
private List<SportType> interestType = new ArrayList<>(); // 사용자 관심 종목

private String profileImage; // 프로필 사진 URL

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ public interface UserService {

// 비밀번호 변경
void changePassword(Long userId, ChangePasswordRequest request);

// 아이디 중복 체크
boolean checkUsernameDuplicate(String username);
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public SignUpResponse signUp(SignUpRequest request) {
.phoneNumber(request.phoneNumber())
.gender(request.gender())
.role(Role.USER)
.interestType(request.interestSports() != null ? request.interestSports() : new java.util.ArrayList<>())
.build();

User savedUser = userRepository.save(user);
Expand Down Expand Up @@ -121,6 +122,11 @@ public UserInfoResponse getUserInfo(Long userId) {
return UserInfoResponse.from(userAuthInfo);
}

@Override
public boolean checkUsernameDuplicate(String username) {
return userRepository.existsByUsername(username);
}

@Override
@Transactional
public void changePassword(Long userId, ChangePasswordRequest request) {
Expand Down