Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

비밀번호 및 닉네임 수정 API 추가, 구글 소셜 로그인 수정 #68

Closed
wants to merge 1 commit into from
Closed
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 @@ -12,15 +12,13 @@ import org.springframework.stereotype.Service
@Service
class SmtpMailService(
private val mailSender: JavaMailSender,
@Value("\${spring.mail.username}")
private val fromMail: String
) : MailService {
override fun sendMail(toEmail: String, title: String, content: String) {
val message: MimeMessage = mailSender.createMimeMessage()
val helper = MimeMessageHelper(message, true, "UTF-8")
try {
helper.apply {
setFrom(fromMail)
setFrom("[email protected]")
setTo(toEmail)
setSubject(title)
setText(content, true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.wafflestudio.toyproject.memoWithTags.social.controller

import com.wafflestudio.toyproject.memoWithTags.exception.OAuthRequestException
import com.wafflestudio.toyproject.memoWithTags.social.dto.SocialLoginResponse
import com.wafflestudio.toyproject.memoWithTags.social.service.SocialLoginService
import com.wafflestudio.toyproject.memoWithTags.user.SocialType
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserResponse.LoginResponse
import io.swagger.v3.oas.annotations.Operation
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -18,6 +20,8 @@ import org.springframework.web.bind.annotation.RestController
class SocialLoginController(
private val socialLoginService: SocialLoginService
) {
private val logger = LoggerFactory.getLogger(javaClass)

@Operation(summary = "소셜 로그인 요청")
@GetMapping("/auth/code/{provider}")
fun oauthCallback(
Expand All @@ -26,6 +30,8 @@ class SocialLoginController(
): ResponseEntity<Unit> {
if (code == null) throw OAuthRequestException()
val appLink = "memowithtags://oauth/$provider?code=$code"

logger.info("redirect request to $appLink")
return ResponseEntity.status(HttpStatus.FOUND)
.header("Location", appLink)
.build()
Expand All @@ -36,14 +42,16 @@ class SocialLoginController(
fun oauthLogin(
@RequestParam(value = "code") code: String,
@PathVariable provider: String
): ResponseEntity<LoginResponse> {
): ResponseEntity<SocialLoginResponse> {
val socialType = SocialType.from(provider)
val loginResult = when (socialType) {
val socialLoginResponse = when (socialType) {
SocialType.KAKAO -> socialLoginService.kakaoLogin(code)
SocialType.NAVER -> socialLoginService.naverLogin(code)
SocialType.GOOGLE -> socialLoginService.googleLogin(code)
else -> throw OAuthRequestException()
}
return ResponseEntity.ok(LoginResponse(loginResult.second, loginResult.third))

logger.info("social login result: (${socialLoginResponse.accessToken}, ${socialLoginResponse.isNewUser})")
return ResponseEntity.ok(socialLoginResponse)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.wafflestudio.toyproject.memoWithTags.social.dto

data class SocialLoginResponse(
val accessToken: String,
val refreshToken: String,
val isNewUser: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.wafflestudio.toyproject.memoWithTags.social.dto.KakaoOAuthToken
import com.wafflestudio.toyproject.memoWithTags.social.dto.KakaoProfile
import com.wafflestudio.toyproject.memoWithTags.social.dto.NaverOAuthToken
import com.wafflestudio.toyproject.memoWithTags.social.dto.NaverProfile
import com.wafflestudio.toyproject.memoWithTags.social.dto.SocialLoginResponse
import com.wafflestudio.toyproject.memoWithTags.user.GoogleUtil
import com.wafflestudio.toyproject.memoWithTags.user.JwtUtil
import com.wafflestudio.toyproject.memoWithTags.user.KakaoUtil
Expand All @@ -28,9 +29,10 @@ class SocialLoginService(
/**
* 네이버 프로필 정보를 받아온 후, 로그인 또는 회원가입 후 로그인 로직을 처리하는 함수
*/
fun naverLogin(accessCode: String): Triple<User, String, String> {
fun naverLogin(accessCode: String): SocialLoginResponse {
val oAuthToken: NaverOAuthToken = naverUtil.requestToken(accessCode)
val naverProfile: NaverProfile = naverUtil.requestProfile(oAuthToken)
var isNewUser = false

val naverEmail = naverProfile.email
val userEntity = socialUserService.findUserByEmail(naverEmail)
Expand All @@ -41,24 +43,26 @@ class SocialLoginService(
User.fromEntity(userEntity)
} else if (userEntity == null) {
logger.info("creating naver user $naverEmail")
isNewUser = true
socialUserService.createNaverUser(naverProfile)
} else {
throw EmailAlreadyExistsException()
}

return Triple(
user,
JwtUtil.generateAccessToken(naverEmail),
JwtUtil.generateRefreshToken(naverEmail)
return SocialLoginResponse(
accessToken = JwtUtil.generateAccessToken(naverEmail),
refreshToken = JwtUtil.generateRefreshToken(naverEmail),
isNewUser = isNewUser
)
}

/**
* 카카오 프로필 정보를 받아온 후, 로그인 또는 회원가입 후 로그인 로직을 처리하는 함수
*/
fun kakaoLogin(accessCode: String): Triple<User, String, String> {
fun kakaoLogin(accessCode: String): SocialLoginResponse {
val oAuthToken: KakaoOAuthToken = kakaoUtil.requestToken(accessCode)
val kakaoProfile: KakaoProfile = kakaoUtil.requestProfile(oAuthToken)
var isNewUser = false

val kakaoEmail = kakaoProfile.kakao_account.email
val userEntity = socialUserService.findUserByEmail(kakaoEmail)
Expand All @@ -69,24 +73,26 @@ class SocialLoginService(
User.fromEntity(userEntity)
} else if (userEntity == null) {
logger.info("creating kakao user $kakaoEmail")
isNewUser = true
socialUserService.createKakaoUser(kakaoProfile)
} else {
throw EmailAlreadyExistsException()
}

return Triple(
user,
JwtUtil.generateAccessToken(kakaoEmail),
JwtUtil.generateRefreshToken(kakaoEmail)
return SocialLoginResponse(
accessToken = JwtUtil.generateAccessToken(kakaoEmail),
refreshToken = JwtUtil.generateRefreshToken(kakaoEmail),
isNewUser = isNewUser
)
}

/**
* 구글 프로필 정보를 받아온 후, 로그인 또는 회원가입 후 로그인 로직을 처리하는 함수
*/
fun googleLogin(accessCode: String): Triple<User, String, String> {
fun googleLogin(accessCode: String): SocialLoginResponse {
val oAuthToken: GoogleOAuthToken = googleUtil.requestToken(accessCode)
val googleProfile: GoogleProfile = googleUtil.requestProfile(oAuthToken)
var isNewUser = false

val googleEmail = googleProfile.email
val userEntity = socialUserService.findUserByEmail(googleEmail)
Expand All @@ -97,15 +103,16 @@ class SocialLoginService(
User.fromEntity(userEntity)
} else if (userEntity == null) {
logger.info("creating google user $googleEmail")
isNewUser = true
socialUserService.createGoogleUser(googleProfile)
} else {
throw EmailAlreadyExistsException()
}

return Triple(
user,
JwtUtil.generateAccessToken(googleEmail),
JwtUtil.generateRefreshToken(googleEmail)
return SocialLoginResponse(
accessToken = JwtUtil.generateAccessToken(googleEmail),
refreshToken = JwtUtil.generateRefreshToken(googleEmail),
isNewUser = isNewUser
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.wafflestudio.toyproject.memoWithTags.user.controller

import com.wafflestudio.toyproject.memoWithTags.user.AuthUser
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserRequest.UpdatePasswordRequest
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserRequest.UpdateNicknameRequest
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserRequest.ForgotPasswordRequest
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserRequest.LoginRequest
import com.wafflestudio.toyproject.memoWithTags.user.dto.UserRequest.RefreshTokenRequest
Expand All @@ -16,6 +18,7 @@ import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
Expand Down Expand Up @@ -62,6 +65,24 @@ class UserController(
return ResponseEntity.ok().build()
}

@Operation(summary = "비밀번호 수정(로그인 상태에서)")
@PutMapping("/auth/password")
fun updatePassword(
@AuthUser user: User,
@RequestBody request: UpdatePasswordRequest
): ResponseEntity<User> {
return ResponseEntity.ok(userService.updatePassword(user, request.password))
}

@Operation(summary = "닉네임 수정")
@PutMapping("/auth/nickname")
fun updateNickname(
@AuthUser user: User,
@RequestBody request: UpdateNicknameRequest
): ResponseEntity<User> {
return ResponseEntity.ok(userService.updateNickname(user, request.nickname))
}

@Operation(summary = "토큰 재발급")
@PostMapping("/auth/refresh-token")
fun refreshToken(@RequestBody request: RefreshTokenRequest): RefreshTokenResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ sealed class UserRequest {
val password: String
) : UserRequest()

data class UpdatePasswordRequest(
val password: String
) : UserRequest()

data class UpdateNicknameRequest(
val nickname: String
) : UserRequest()

data class RefreshTokenRequest(
val refreshToken: String
) : UserRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,32 @@ class UserService(
return User.fromEntity(userEntity)
}

/**
* 로그인 한 유저의 비밀번호를 변경하는 함수
*/
@Transactional
fun updatePassword(
user: User,
newPassword: String
): User {
val userEntity = userRepository.findByEmail(user.email) ?: throw UserNotFoundException()
userEntity.hashedPassword = BCrypt.hashpw(newPassword, BCrypt.gensalt())
return User.fromEntity(userRepository.save(userEntity))
}

/**
* 로그인 한 유저의 닉네임을 변경하는 함수
*/
@Transactional
fun updateNickname(
user: User,
newNickname: String
): User {
val userEntity = userRepository.findByEmail(user.email) ?: throw UserNotFoundException()
userEntity.nickname = newNickname
return User.fromEntity(userRepository.save(userEntity))
}

/**
* accessToken 만료 시 refreshToken을 통해 유저를 확인하고 새로운 accessToken을 발급하는 함수
*/
Expand Down
Loading