diff --git a/src/main/kotlin/com/psr/psr/global/Constant.kt b/src/main/kotlin/com/psr/psr/global/Constant.kt index 5a13b51..5c6b585 100644 --- a/src/main/kotlin/com/psr/psr/global/Constant.kt +++ b/src/main/kotlin/com/psr/psr/global/Constant.kt @@ -1,9 +1,20 @@ package com.psr.psr.global class Constant { - companion object JWT{ - const val AUTHORIZATION_HEADER = "Authorization" - const val BEARER_PREFIX: String = "Bearer " + class JWT{ + companion object JWT{ + const val AUTHORIZATION_HEADER = "Authorization" + const val BEARER_PREFIX: String = "Bearer " + } + } + + class User{ + companion object User{ + // 비밀번호 (숫자, 문자, 특수문자 포함 8~15자리 이내) + const val PASSWORD_VALIDATION = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$" + const val EMAIL_VALIDATION = "^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}\$" + const val PHONE_VALIDATION = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})\$" + } } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt b/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt index 9805a54..1b9aee2 100644 --- a/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt +++ b/src/main/kotlin/com/psr/psr/global/config/WebSecurityConfig.kt @@ -1,6 +1,5 @@ package com.psr.psr.global.config -import com.psr.psr.global.jwt.UserDetailsServiceImpl import com.psr.psr.global.jwt.exception.JwtAccessDeniedHandler import com.psr.psr.global.jwt.exception.JwtAuthenticationEntryPoint import com.psr.psr.global.jwt.utils.JwtUtils @@ -9,16 +8,22 @@ import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.util.matcher.AntPathRequestMatcher @Configuration @EnableWebSecurity class WebSecurityConfig( - private val userDetailsService: UserDetailsServiceImpl, private val jwtUtils: JwtUtils, private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint, private val jwtAccessDeniedHandler: JwtAccessDeniedHandler ) { + @Bean + fun PasswordEncoder() : PasswordEncoder { + return BCryptPasswordEncoder() + } @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { @@ -35,8 +40,8 @@ class WebSecurityConfig( // token 없이 사용이 가능한 api url 작성 .authorizeHttpRequests { c -> c.requestMatchers("/global").permitAll() - c.requestMatchers("/users/login").permitAll() - c.requestMatchers("/users/signup").permitAll() + c.requestMatchers(AntPathRequestMatcher("/users/login")).permitAll() + c.requestMatchers(AntPathRequestMatcher("/users/signup")).permitAll() c.anyRequest().authenticated() } .apply(JwtSecurityConfig(jwtUtils)) diff --git a/src/main/kotlin/com/psr/psr/global/dto/BaseResponse.kt b/src/main/kotlin/com/psr/psr/global/dto/BaseResponse.kt index 9098408..98345a8 100644 --- a/src/main/kotlin/com/psr/psr/global/dto/BaseResponse.kt +++ b/src/main/kotlin/com/psr/psr/global/dto/BaseResponse.kt @@ -21,7 +21,7 @@ class BaseResponse { constructor(result: T) { this.code = BaseResponseCode.SUCCESS.status.value() this.message = BaseResponseCode.SUCCESS.message - this.data = data + this.data = result } // fail diff --git a/src/main/kotlin/com/psr/psr/global/exception/BaseRes.kt b/src/main/kotlin/com/psr/psr/global/exception/BaseRes.kt index aaccd43..a986061 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/BaseRes.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/BaseRes.kt @@ -3,6 +3,6 @@ package com.psr.psr.global.exception import org.springframework.http.HttpStatus data class BaseRes( - val status: HttpStatus, + val status: Int, val message: String? ) diff --git a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt index 76e5ba3..e13b99a 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt @@ -10,7 +10,22 @@ enum class BaseResponseCode(status: HttpStatus, message: String) { INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰 값입니다."), UNSUPPORTED_TOKEN(HttpStatus.UNAUTHORIZED, "잘못된 형식의 토큰 값입니다."), MALFORMED_TOKEN(HttpStatus.UNAUTHORIZED, "잘못된 구조의 토큰 값입니다."), - EXPIRED_TOKEN(HttpStatus.FORBIDDEN, "만료된 토큰 값입니다."); + EXPIRED_TOKEN(HttpStatus.FORBIDDEN, "만료된 토큰 값입니다."), + + // user + INVALID_EMAIL(HttpStatus.BAD_REQUEST, "올바르지 않은 이메일 형식입니다."), + INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "올바르지 않은 비밀번호 형식입니다."), + INVALID_PHONE(HttpStatus.BAD_REQUEST, "올바르지 않은 휴대폰 형식입니다."), + EXISTS_PHONE(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 휴대폰 번호입니다."), + EXISTS_EMAIL(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 이메일입니다."), + EXISTS_NICKNAME(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 닉네임입니다."), + + // User - type + INVALID_USER_TYPE_NAME(HttpStatus.BAD_REQUEST, "올바르지 않은 사용자 역할입니다."), + INVALID_USER_CATEGORY(HttpStatus.BAD_REQUEST, "올바르지 않은 사용자 카테고리입니다."), + + // User - category + INVALID_USER_INTEREST_COUNT(HttpStatus.BAD_REQUEST, "사용자 관심 주제는 1개이상, 3개 이하여야하며, 중복된 값이 포함되어 있지 않아야 합니다"); val status: HttpStatus = status val message: String = message diff --git a/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt b/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt index 4d5733a..3be41fa 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt @@ -10,6 +10,6 @@ class ExceptionHandler { @ExceptionHandler(BaseException::class) protected fun handleBaseException(e: BaseException): ResponseEntity{ return ResponseEntity.status(e.baseResponseCode.status) - .body(BaseRes(e.baseResponseCode.status, e.baseResponseCode.message)) + .body(BaseRes(e.baseResponseCode.status.value(), e.baseResponseCode.message)) } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/global/jwt/JwtFilter.kt b/src/main/kotlin/com/psr/psr/global/jwt/JwtFilter.kt index 1951c6b..c0507ea 100644 --- a/src/main/kotlin/com/psr/psr/global/jwt/JwtFilter.kt +++ b/src/main/kotlin/com/psr/psr/global/jwt/JwtFilter.kt @@ -1,7 +1,7 @@ package com.psr.psr.global.jwt -import com.psr.psr.global.Constant.JWT.AUTHORIZATION_HEADER -import com.psr.psr.global.Constant.JWT.BEARER_PREFIX +import com.psr.psr.global.Constant.JWT.JWT.AUTHORIZATION_HEADER +import com.psr.psr.global.Constant.JWT.JWT.BEARER_PREFIX import com.psr.psr.global.dto.BaseResponse import com.psr.psr.global.exception.BaseException import com.psr.psr.global.jwt.utils.JwtUtils diff --git a/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsImpl.kt b/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsImpl.kt index c823ca2..6db67d6 100644 --- a/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsImpl.kt +++ b/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsImpl.kt @@ -12,7 +12,7 @@ class UserDetailsImpl(val user:User) :UserDetails { val grantedAuthority = SimpleGrantedAuthority(user.type.name) return mutableListOf(grantedAuthority) } - + fun getUserId() : Long = user.id!! override fun getPassword(): String = user.password override fun getUsername(): String = user.id.toString() diff --git a/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsServiceImpl.kt b/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsServiceImpl.kt index f03975a..dd4fc57 100644 --- a/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsServiceImpl.kt +++ b/src/main/kotlin/com/psr/psr/global/jwt/UserDetailsServiceImpl.kt @@ -7,6 +7,7 @@ import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service class UserDetailsServiceImpl(private val userRepository: UserRepository) :UserDetailsService { @@ -14,4 +15,10 @@ class UserDetailsServiceImpl(private val userRepository: UserRepository) :UserDe val user:User = userRepository.findByIdOrNull(username?.toLong() ?: 0L) ?: throw UsernameNotFoundException("사용자 id를 찾을 수 없습니다.") return UserDetailsImpl(user) } + + @Transactional + fun loadUserById(id: Long): UserDetails { + val user = userRepository.findById(id).orElseThrow { UsernameNotFoundException("User not found with id : $id") } + return UserDetailsImpl(user) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/global/jwt/dto/TokenRes.kt b/src/main/kotlin/com/psr/psr/global/jwt/dto/TokenRes.kt index c1ee808..60c305d 100644 --- a/src/main/kotlin/com/psr/psr/global/jwt/dto/TokenRes.kt +++ b/src/main/kotlin/com/psr/psr/global/jwt/dto/TokenRes.kt @@ -1,3 +1,5 @@ package com.psr.psr.global.jwt.dto -data class TokenRes(val accessToken: String, val refreshToken: String) \ No newline at end of file +import com.psr.psr.user.entity.Type + +data class TokenRes(val accessToken: String, val refreshToken: String, val type: String) \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/global/jwt/utils/JwtUtils.kt b/src/main/kotlin/com/psr/psr/global/jwt/utils/JwtUtils.kt index fcceb18..3e03d54 100644 --- a/src/main/kotlin/com/psr/psr/global/jwt/utils/JwtUtils.kt +++ b/src/main/kotlin/com/psr/psr/global/jwt/utils/JwtUtils.kt @@ -1,11 +1,12 @@ package com.psr.psr.global.jwt.utils -import com.psr.psr.global.Constant.JWT.BEARER_PREFIX -import com.psr.psr.global.Constant.JWT.AUTHORIZATION_HEADER +import com.psr.psr.global.Constant.JWT.JWT.BEARER_PREFIX +import com.psr.psr.global.Constant.JWT.JWT.AUTHORIZATION_HEADER import com.psr.psr.global.exception.BaseException import com.psr.psr.global.exception.BaseResponseCode import com.psr.psr.global.jwt.UserDetailsServiceImpl import com.psr.psr.global.jwt.dto.TokenRes +import com.psr.psr.user.entity.Type import io.jsonwebtoken.* import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.security.Keys @@ -39,7 +40,7 @@ class JwtUtils( /** * 토큰 생성 */ - fun createToken(authentication: Authentication): TokenRes { + fun createToken(authentication: Authentication, type: Type): TokenRes { val authorities = authentication.authorities.stream() .map { obj: GrantedAuthority -> obj.authority } .collect(Collectors.joining(",")) @@ -57,7 +58,7 @@ class JwtUtils( .signWith(key, SignatureAlgorithm.HS512) .compact() - return TokenRes(BEARER_PREFIX + accessToken, BEARER_PREFIX + refreshToken) + return TokenRes(BEARER_PREFIX + accessToken, BEARER_PREFIX + refreshToken, type.value) } /** @@ -85,13 +86,15 @@ class JwtUtils( * 토큰 복호화 */ fun getAuthentication(accessToken: String): Authentication { - val claims = parseClaims(accessToken) - // todo: 에러 추가 - if (claims[AUTHORIZATION_HEADER] == null) logger.info("토큰 복호화 error") - val userDetails: UserDetails = userDetailsService.loadUserByUsername(claims.subject) + val userId = getUserIdFromJWT(accessToken) + val userDetails: UserDetails = userDetailsService.loadUserById(userId) return UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities) } + fun getUserIdFromJWT(token: String): Long { + return parseClaims(token).subject.toLong() + } + private fun parseClaims(token: String): Claims { return Jwts.parserBuilder() .setSigningKey(key) diff --git a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt index 06b8084..220a1be 100644 --- a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt +++ b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt @@ -1,12 +1,23 @@ package com.psr.psr.user.controller +import com.psr.psr.global.dto.BaseResponse +import com.psr.psr.global.exception.BaseResponseCode +import com.psr.psr.global.jwt.dto.TokenRes +import com.psr.psr.user.dto.SignUpReq import com.psr.psr.user.service.UserService -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/users") class UserController( private val userService: UserService ) { + /** + * 회원가입 + */ + @PostMapping("/signup") + @ResponseBody + fun signUp (@RequestBody signUpReq: SignUpReq) : BaseResponse{ + return BaseResponse(userService.signUp(signUpReq)) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt b/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt new file mode 100644 index 0000000..bcdd8be --- /dev/null +++ b/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt @@ -0,0 +1,40 @@ +package com.psr.psr.user.dto + +import com.psr.psr.user.entity.* +import java.util.stream.Collector +import java.util.stream.Collectors + + + + +data class SignUpReq ( + val email: String, + var password: String, + val type: String, + val phone: String, + val imgKey: String, + val nickname: String, + val marketing: Boolean, + val notification: Boolean, + val interestList: List + ) { + fun toEntity(): User { + return User(email = email, + password = password, + type = Type.getTypeByName(type), + phone = phone, + imgKey = imgKey, + provider = Provider.LOCAL, + marketing = marketing, + notification = notification, + nickname = nickname) + } + + fun toInterestEntity(user: User): List { + return interestList.stream() + .map { i -> + UserInterest(category = Category.getCategoryByName(i.category), + user = user) + }.collect(Collectors.toList()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/dto/UserInterestReq.kt b/src/main/kotlin/com/psr/psr/user/dto/UserInterestReq.kt new file mode 100644 index 0000000..fa057eb --- /dev/null +++ b/src/main/kotlin/com/psr/psr/user/dto/UserInterestReq.kt @@ -0,0 +1,12 @@ +package com.psr.psr.user.dto + +import com.psr.psr.user.entity.Category + +data class UserInterestReq ( + val category: String +){ + fun checkInterestCategory() : Category{ + return Category.getCategoryByName(category) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/entity/Category.kt b/src/main/kotlin/com/psr/psr/user/entity/Category.kt index e78aeeb..ecc4701 100644 --- a/src/main/kotlin/com/psr/psr/user/entity/Category.kt +++ b/src/main/kotlin/com/psr/psr/user/entity/Category.kt @@ -1,5 +1,8 @@ package com.psr.psr.user.entity +import com.psr.psr.global.exception.BaseException +import com.psr.psr.global.exception.BaseResponseCode + enum class Category(val value: String) { BROADCAST_PRODUCT("방송가능 상품소싱"), SHOW_HOST_ADVERTISE("쇼호스트 구인"), @@ -9,5 +12,12 @@ enum class Category(val value: String) { VIDEO_EDITING("영상편집"), INSTRUCTOR_MATCHING("강사매칭"), SNS_MARKETING("SNS 마케팅"), - PROMOTION_DESIGN("홍보물 디자인") + PROMOTION_DESIGN("홍보물 디자인"); + + companion object { + fun getCategoryByName(name: String): Category { + return enumValues().find { it.value == name } + ?: throw BaseException(BaseResponseCode.INVALID_USER_CATEGORY) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/entity/Type.kt b/src/main/kotlin/com/psr/psr/user/entity/Type.kt index 3a60304..56052d3 100644 --- a/src/main/kotlin/com/psr/psr/user/entity/Type.kt +++ b/src/main/kotlin/com/psr/psr/user/entity/Type.kt @@ -1,8 +1,19 @@ package com.psr.psr.user.entity +import com.psr.psr.global.exception.BaseException +import com.psr.psr.global.exception.BaseResponseCode + + enum class Type(val value: String) { GENERAL("일반"), ENTREPRENEUR("사업자"), SHOW_HOST("쇼호스트"), - MANAGER("관리자") + MANAGER("관리자"); + + companion object { + fun getTypeByName(name: String): Type { + return enumValues().find { it.value == name } + ?: throw BaseException(BaseResponseCode.INVALID_USER_TYPE_NAME) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/entity/User.kt b/src/main/kotlin/com/psr/psr/user/entity/User.kt index 36a904f..e729ffb 100644 --- a/src/main/kotlin/com/psr/psr/user/entity/User.kt +++ b/src/main/kotlin/com/psr/psr/user/entity/User.kt @@ -5,9 +5,9 @@ import jakarta.persistence.* import org.jetbrains.annotations.NotNull @Entity -data class User( +class User( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long, + var id: Long? = null, @NotNull @Column(length = 100) @@ -29,7 +29,7 @@ data class User( @Column(length = 15) var phone:String, - var imgKey: String, + var imgKey: String? = null, @NotNull @Enumerated(EnumType.STRING) diff --git a/src/main/kotlin/com/psr/psr/user/entity/UserInterest.kt b/src/main/kotlin/com/psr/psr/user/entity/UserInterest.kt index afa0646..a68fe13 100644 --- a/src/main/kotlin/com/psr/psr/user/entity/UserInterest.kt +++ b/src/main/kotlin/com/psr/psr/user/entity/UserInterest.kt @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull @Entity data class UserInterest( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long, + var id: Long? = null, @ManyToOne @JoinColumn(nullable = false, name = "user_id") diff --git a/src/main/kotlin/com/psr/psr/user/repository/UserRepository.kt b/src/main/kotlin/com/psr/psr/user/repository/UserRepository.kt index 69e6e21..1baec4a 100644 --- a/src/main/kotlin/com/psr/psr/user/repository/UserRepository.kt +++ b/src/main/kotlin/com/psr/psr/user/repository/UserRepository.kt @@ -3,7 +3,11 @@ package com.psr.psr.user.repository import com.psr.psr.user.entity.User import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository +import java.util.* @Repository interface UserRepository: JpaRepository { + fun existsByNickname(nickname: String): Boolean + fun existsByPhone(phone: String): Boolean + fun existsByEmail(nickname: String): Boolean } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/service/UserService.kt b/src/main/kotlin/com/psr/psr/user/service/UserService.kt index d69cf48..503fd9d 100644 --- a/src/main/kotlin/com/psr/psr/user/service/UserService.kt +++ b/src/main/kotlin/com/psr/psr/user/service/UserService.kt @@ -1,10 +1,82 @@ package com.psr.psr.user.service +import com.fasterxml.jackson.databind.ser.Serializers.Base +import com.psr.psr.global.Constant.User.User.EMAIL_VALIDATION +import com.psr.psr.global.Constant.User.User.PASSWORD_VALIDATION +import com.psr.psr.global.Constant.User.User.PHONE_VALIDATION +import com.psr.psr.global.exception.BaseException +import com.psr.psr.global.exception.BaseResponseCode +import com.psr.psr.global.jwt.dto.TokenRes +import com.psr.psr.global.jwt.utils.JwtUtils +import com.psr.psr.user.dto.SignUpReq +import com.psr.psr.user.entity.Category +import com.psr.psr.user.entity.User +import com.psr.psr.user.entity.UserInterest +import com.psr.psr.user.repository.UserInterestRepository import com.psr.psr.user.repository.UserRepository +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.regex.Pattern +import java.util.stream.Collectors @Service +@Transactional(readOnly = true) class UserService( - private val userRepository: UserRepository + private val userRepository: UserRepository, + private val userInterestRepository: UserInterestRepository, + private val authenticationManagerBuilder: AuthenticationManagerBuilder, + private val jwtUtils: JwtUtils, + private val passwordEncoder: PasswordEncoder + ) { + // 회원가입 + @Transactional + fun signUp(signUpReq: SignUpReq): TokenRes { + // 이메일의 형식이 맞는지 확인 + if(!isValidRegularExpression(signUpReq.email, EMAIL_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_EMAIL) + // 비밀번호의 형식이 맞는지 확인 + if(!isValidRegularExpression(signUpReq.password, PASSWORD_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_PASSWORD) + // 휴대폰 번호의 형식이 맞는지 확인 + if(!isValidRegularExpression(signUpReq.phone, PHONE_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_PHONE) + // Category가 알맞은 이름을 갖고 있는지, 값이 중복되어있는지 확인 + val categoryCheck = signUpReq.interestList.stream().map { i -> i.checkInterestCategory() }.collect(Collectors.toList()).groupingBy { it }.eachCount().any { it.value > 1 } + if(categoryCheck) throw BaseException(BaseResponseCode.INVALID_USER_INTEREST_COUNT) + // category 의 사이즈 확인 + val listSize = signUpReq.interestList.size + if(listSize < 1 || listSize > 3) throw BaseException(BaseResponseCode.INVALID_USER_INTEREST_COUNT) + + // 이미 가지고 있는 이메일, 닉네임, 휴대폰 번호인지 확인 + if(userRepository.existsByEmail(signUpReq.email)) throw BaseException(BaseResponseCode.EXISTS_EMAIL) + if(userRepository.existsByPhone(signUpReq.phone)) throw BaseException(BaseResponseCode.EXISTS_PHONE) + if(userRepository.existsByNickname(signUpReq.nickname)) throw BaseException(BaseResponseCode.EXISTS_NICKNAME) + + + // 암호화되지 않은 password 값 저장 + val password = signUpReq.password + // password 암호화 + val encodedPassword = passwordEncoder.encode(signUpReq.password) + signUpReq.password = encodedPassword + // user 저장 + val user = userRepository.save(signUpReq.toEntity()) + userInterestRepository.saveAll(signUpReq.toInterestEntity(user)) + + // token 생성 + return createToken(user, password) + } + + // 정규 표현식 확인 extract method + private fun isValidRegularExpression(word: String, validation: String) : Boolean{ + val pattern = Pattern.compile(validation) + return pattern.matcher(word).matches() + } + + // token 생성 extract method + private fun createToken(user: User, password: String): TokenRes { + val authenticationToken = UsernamePasswordAuthenticationToken(user.id.toString(), password) + val authentication = authenticationManagerBuilder.`object`.authenticate(authenticationToken) + return jwtUtils.createToken(authentication, user.type) + } } \ No newline at end of file