diff --git a/src/main/java/com/alist/api/config/SecurityConfig.java b/src/main/java/com/alist/api/config/SecurityConfig.java index b64fd05..6f0fc9e 100644 --- a/src/main/java/com/alist/api/config/SecurityConfig.java +++ b/src/main/java/com/alist/api/config/SecurityConfig.java @@ -60,7 +60,7 @@ public class SecurityConfig { .accessDeniedHandler(new JwtAccessDeniedHandler()) ) .authorizeHttpRequests(auth -> auth - .requestMatchers("/", "/actuator/health", "/auth/**", "/api/user/signup").permitAll() + .requestMatchers("/", "/actuator/health", "/auth/**", "/api/testUser/signup").permitAll() .anyRequest().authenticated() ) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/java/com/alist/api/modules/testUser/TestUserController.java b/src/main/java/com/alist/api/modules/testUser/TestUserController.java new file mode 100644 index 0000000..d6e8937 --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/TestUserController.java @@ -0,0 +1,39 @@ +package com.alist.api.modules.testUser; + +import com.alist.api.common.response.ApiResponse; +import com.alist.api.common.response.ApiResponseCode; +import com.alist.api.modules.testUser.dto.TestUserDto; +import com.alist.api.modules.testUser.form.TestUserSignupForm; +import com.alist.api.modules.testUser.service.TestUserService; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/api/testUser") +public class TestUserController { + + public final TestUserService testUserService; + + public TestUserController(TestUserService testUserService) { + this.testUserService = testUserService; + } + + @PostMapping("/signup") + public ResponseEntity> signup(@Valid @RequestBody TestUserSignupForm testUserSignupForm) { + + TestUserDto userDto = testUserService.insertTestUserProc(testUserSignupForm.testUserDto()); + + if (userDto.getResultCode() == 2004) { + return ApiResponse.entity(userDto, ApiResponseCode.CODE_2004, "아이디"); + } + + return ApiResponse.entity(userDto, ApiResponseCode.CODE_2002, "아이디"); + } + +} \ No newline at end of file diff --git a/src/main/java/com/alist/api/modules/testUser/dto/TestUserDto.java b/src/main/java/com/alist/api/modules/testUser/dto/TestUserDto.java new file mode 100644 index 0000000..8e58b54 --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/dto/TestUserDto.java @@ -0,0 +1,19 @@ +package com.alist.api.modules.testUser.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class TestUserDto { + private Integer userIdx; + private String id; + + @JsonIgnore + private String newPassword; + @JsonIgnore + private String password; + @JsonIgnore + private int resultCode; +} diff --git a/src/main/java/com/alist/api/modules/testUser/dto/TestUserTokenDto.java b/src/main/java/com/alist/api/modules/testUser/dto/TestUserTokenDto.java new file mode 100644 index 0000000..2e89ec7 --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/dto/TestUserTokenDto.java @@ -0,0 +1,14 @@ +package com.alist.api.modules.testUser.dto; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class TestUserTokenDto { + private int userTokenIdx; + private int userIdx; + private String userApiKey; + private String userRole; + private int resultCode; +} diff --git a/src/main/java/com/alist/api/modules/testUser/form/TestUserSignupForm.java b/src/main/java/com/alist/api/modules/testUser/form/TestUserSignupForm.java new file mode 100644 index 0000000..9098cca --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/form/TestUserSignupForm.java @@ -0,0 +1,40 @@ +package com.alist.api.modules.testUser.form; + +import com.alist.api.modules.testUser.dto.TestUserDto; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@Schema(description = "회원 가입 요청 폼") +public class TestUserSignupForm { + @Schema( + description = "사용자 아이디 (공백 불가)", + example = "test" + ) + @NotBlank(message = "아이디를 입력해주세요.") + private String id; + + @Schema( + description = "비밀번호 (8~64자, 영문 + 숫자 조합, 공백 불가)", + example = "pass1234" + ) + @NotBlank(message = "비밀번호를 입력해주세요.") + @Size(min = 8, max = 64, message = "비밀번호는 8~64자여야 합니다.") + @Pattern( + regexp = "^(?=.*[A-Za-z])(?=.*\\d)\\S+$", + message = "비밀번호는 영문과 숫자를 포함하고 공백이 없어야 합니다." + ) + private String password; + + public TestUserDto testUserDto() { + TestUserDto testUserDto = new TestUserDto(); + testUserDto.setId(id.trim()); + testUserDto.setPassword(password); + return testUserDto; + } +} diff --git a/src/main/java/com/alist/api/modules/testUser/mapper/TestUserMapper.java b/src/main/java/com/alist/api/modules/testUser/mapper/TestUserMapper.java new file mode 100644 index 0000000..5ff3e0a --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/mapper/TestUserMapper.java @@ -0,0 +1,14 @@ +package com.alist.api.modules.testUser.mapper; + +import com.alist.api.modules.testUser.dto.TestUserDto; +import com.alist.api.modules.testUser.dto.TestUserTokenDto; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TestUserMapper { + int selectDuplicateTestUserCount(TestUserDto testUserDto); + + int insertTestUserSignup(TestUserDto testUserDto); + + int insertTestUserTokenSignup(TestUserTokenDto testUserTokenDto); +} diff --git a/src/main/java/com/alist/api/modules/testUser/service/TestUserService.java b/src/main/java/com/alist/api/modules/testUser/service/TestUserService.java new file mode 100644 index 0000000..6b4d4f6 --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/service/TestUserService.java @@ -0,0 +1,65 @@ +package com.alist.api.modules.testUser.service; + +import com.alist.api.common.utils.ApiKeyGenerator; +import com.alist.api.modules.testUser.dto.TestUserDto; +import com.alist.api.modules.testUser.dto.TestUserTokenDto; +import com.alist.api.modules.testUser.mapper.TestUserMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +public class TestUserService { + private final TestUserMapper testUserMapper; + private final PasswordEncoder passwordEncoder; + + public TestUserService(TestUserMapper testUserMapper, PasswordEncoder passwordEncoder) { + this.testUserMapper = testUserMapper; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public TestUserDto insertTestUserProc(TestUserDto testUserDto) { + // 중복체크 + if (testUserMapper.selectDuplicateTestUserCount(testUserDto) > 0) { + testUserDto.setResultCode(2004); + return testUserDto; + } + + // 비밀번호 생성 + testUserDto.setNewPassword(passwordEncoder.encode(testUserDto.getPassword())); + + // 회원정보 입력 + int result = testUserMapper.insertTestUserSignup(testUserDto); + + if (result > 0) { + // user_api_key 생성 + TestUserTokenDto testUserTokenDto = new TestUserTokenDto(); + testUserTokenDto.setUserIdx(testUserDto.getUserIdx()); + + apiKeyWithRetry(testUserTokenDto); + } + + log.info("cnt : " + testUserDto.getUserIdx()); + log.info("userIdx : " + testUserDto.getUserIdx()); + + return testUserDto; + } + + @Transactional + public int apiKeyWithRetry(TestUserTokenDto testUserTokenDto) { + for (int i = 0; i < 5; i++) { + testUserTokenDto.setUserApiKey(ApiKeyGenerator.userApiKeyProc()); + try { + return testUserMapper.insertTestUserTokenSignup(testUserTokenDto); + } catch (DuplicateKeyException e) { + // 충돌이면 다시 생성 + log.warn("Duplicate API key. retrying... userId={}", testUserTokenDto.getUserIdx()); + } + } + throw new IllegalStateException("API key generation failed after retries."); + } +} diff --git a/src/main/java/com/alist/api/modules/testUser/vo/TestUserVo.java b/src/main/java/com/alist/api/modules/testUser/vo/TestUserVo.java new file mode 100644 index 0000000..9d08a7b --- /dev/null +++ b/src/main/java/com/alist/api/modules/testUser/vo/TestUserVo.java @@ -0,0 +1,8 @@ +package com.alist.api.modules.testUser.vo; + +import lombok.Getter; + +@Getter +public class TestUserVo { + private String id; +} diff --git a/src/main/resources/mapper/testUser/TestUserMapper.xml b/src/main/resources/mapper/testUser/TestUserMapper.xml new file mode 100644 index 0000000..a0d5b56 --- /dev/null +++ b/src/main/resources/mapper/testUser/TestUserMapper.xml @@ -0,0 +1,25 @@ + + + + + + /*UserSignupMapper.insertTestUserSignup*/ + insert into test_user (id, password, del_yn, create_at, update_at) + value (#{id}, #{newPassword}, 1, now(), now()) + + + /*UserSignupMapper.insertTestUserTokenSignup*/ + insert into test_user_token (user_idx, user_api_key, user_role, created_at, updated_at) + value (#{userIdx}, #{userApiKey}, 'user', now(), now()) + + + + +