Skip to content

Commit

Permalink
fix: #11 Oauth 전화번호 인증 성공 시, 기존 계정 존재하면 로그인 처리
Browse files Browse the repository at this point in the history
  • Loading branch information
psychology50 committed Dec 24, 2023
1 parent d23125e commit 6582d32
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 24 deletions.
46 changes: 30 additions & 16 deletions src/main/java/com/kcy/fitapet/domain/oauth/api/OauthApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import com.kcy.fitapet.domain.member.service.component.MemberAuthService;
import com.kcy.fitapet.domain.oauth.dto.OauthSignInReq;
import com.kcy.fitapet.domain.oauth.dto.OauthSignUpReq;
import com.kcy.fitapet.domain.oauth.dto.OauthSmsReq;
import com.kcy.fitapet.domain.oauth.service.component.OauthService;
import com.kcy.fitapet.domain.oauth.type.ProviderType;
import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix;
import com.kcy.fitapet.global.common.response.SuccessResponse;
import com.kcy.fitapet.global.common.security.jwt.dto.Jwt;
import com.kcy.fitapet.global.common.util.cookie.CookieUtil;
Expand Down Expand Up @@ -61,10 +61,16 @@ public ResponseEntity<?> signIn(

return (jwt == null)
? ResponseEntity.ok(SuccessResponse.from(Map.of("id", req.id())))
: getResponseEntity(jwt);
: getJwtResponseEntity(jwt);
}

@Operation(summary = "OAuth 회원가입", description = "/{id}/sms로 전화번호 인증 후, accessToken 발급이 선행되어야 한다.")
@Parameters({
@Parameter(name = "id", description = "OAuth 제공자에서 발급받은 ID"),
@Parameter(name = "provider", description = "OAuth 제공자"),
@Parameter(name = "accessToken", description = "OAuth 전화번호 인증 시 발급받은 accessToken"),
@Parameter(name = "req", description = "OAuth 회원가입 요청 정보")
})
@PostMapping("/{id}")
@PreAuthorize("isAnonymous()")
public ResponseEntity<?> signUp(
Expand All @@ -80,36 +86,44 @@ public ResponseEntity<?> signUp(
jwt = oAuthService.signUpByOIDC(id, provider, accessToken, req);
}

return getResponseEntity(jwt);
}

private ResponseEntity<?> getResponseEntity(Jwt jwt) {
ResponseCookie cookie = cookieUtil.createCookie(REFRESH_TOKEN.getValue(), jwt.refreshToken(), 60 * 60 * 24 * 7);

return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.header(ACCESS_TOKEN.getValue(), jwt.accessToken())
.body(SuccessResponse.noContent());
return getJwtResponseEntity(jwt);
}

@PostMapping("/{id}/sms")
@PreAuthorize("isAnonymous()")
public ResponseEntity<?> signUpSmsAuthorization(
@PathVariable("id") Long id,
@RequestParam("provider") ProviderType provider,
@RequestParam(value = "code", required = false) String code,
@RequestBody @Valid SmsReq req
@RequestBody @Valid OauthSmsReq req
) {
if (code == null) {
SmsRes smsRes = oAuthService.sendCode(req, id, provider);
return ResponseEntity.ok(SuccessResponse.from(smsRes));
}

String token = oAuthService.checkCertificationNumber(req, id, code, provider);
if (!StringUtils.hasText(token))
Jwt token = oAuthService.checkCertificationNumber(req, id, code, provider);
if (token == null)
return ResponseEntity.status(HttpStatus.SC_UNAUTHORIZED).build();
else if (token.refreshToken() == null)
return ResponseEntity.ok()
.header(ACCESS_TOKEN.getValue(), token.accessToken())
.body(SuccessResponse.noContent());

ResponseCookie cookie = cookieUtil.createCookie(REFRESH_TOKEN.getValue(), token.refreshToken(), 60 * 60 * 24 * 7);

return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.header(ACCESS_TOKEN.getValue(), token.accessToken())
.body(SuccessResponse.from(Map.of("member", "등록된 oauth 계정 연동 성공")));
}

private ResponseEntity<?> getJwtResponseEntity(Jwt jwt) {
ResponseCookie cookie = cookieUtil.createCookie(REFRESH_TOKEN.getValue(), jwt.refreshToken(), 60 * 60 * 24 * 7);

return ResponseEntity.ok()
.header(ACCESS_TOKEN.getValue(), token)
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.header(ACCESS_TOKEN.getValue(), jwt.accessToken())
.body(SuccessResponse.noContent());
}
}
24 changes: 24 additions & 0 deletions src/main/java/com/kcy/fitapet/domain/oauth/dto/OauthSmsReq.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.kcy.fitapet.domain.oauth.dto;

import com.kcy.fitapet.global.common.util.sms.dto.SmsReq;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

@Schema(description = "OAuth 전화 번호 인증 요청 정보")
public record OauthSmsReq(
@Schema(description = "전화 번호", example = "01012345678")
@NotNull(message = "전화 번호는 필수 입력값입니다.")
String to,
@Schema(description = "OIDC 토큰")
@NotNull(message = "OIDC 토큰은 필수 입력값입니다.")
String idToken,
@Schema(description = "OIDC 토큰 유효성 검사를 위한 nonce")
@NotNull(message = "nonce는 필수 입력값입니다.")
String nonce
) {
public SmsReq toSmsReq() {
return SmsReq.builder()
.to(this.to)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.kcy.fitapet.domain.member.type.RoleType;
import com.kcy.fitapet.domain.oauth.domain.OauthAccount;
import com.kcy.fitapet.domain.oauth.dto.OauthSignUpReq;
import com.kcy.fitapet.domain.oauth.dto.OauthSmsReq;
import com.kcy.fitapet.domain.oauth.exception.OauthException;
import com.kcy.fitapet.domain.oauth.service.module.OauthApplicationConfigHelper;
import com.kcy.fitapet.domain.oauth.service.module.OauthClientHelper;
Expand Down Expand Up @@ -76,15 +77,14 @@ public Jwt signInByOIDC(Long id, String idToken, ProviderType provider, String n
public Jwt signUpByOIDC(Long id, ProviderType provider, String requestAccessToken, OauthSignUpReq req) {
String accessToken = jwtUtil.resolveToken(requestAccessToken);
String topic = jwtUtil.getPhoneNumberFromToken(accessToken);
String phone = getPhoneByTopic(topic);

validateToken(accessToken, topic, provider);

String phone = getPhoneByTopic(topic);
String idToken = oidcTokenService.findOIDCToken(req.idToken()).getToken();
OIDCDecodePayload payload = getPayload(provider, idToken, req.nonce());

Member member = (memberSearchService.isExistByPhone(phone))
? memberSearchService.findByPhone(phone)
: Member.builder().uid(req.uid()).name(req.name())
Member member = Member.builder().uid(req.uid()).name(req.name())
.phone(phone).isOauth(Boolean.TRUE).role(RoleType.USER).build();
memberSaveService.saveMember(member);
OauthAccount oauthAccount = OauthAccount.of(id, provider, payload.email(), member);
Expand All @@ -100,8 +100,8 @@ public Jwt signUpByOIDC(Long id, ProviderType provider, String requestAccessToke
}

@Transactional
public SmsRes sendCode(SmsReq dto, Long id, ProviderType provider) {
SensInfo smsInfo = smsProvider.sendCodeByPhoneNumber(dto);
public SmsRes sendCode(OauthSmsReq dto, Long id, ProviderType provider) {
SensInfo smsInfo = smsProvider.sendCodeByPhoneNumber(dto.toSmsReq());
String key = makeTopic(dto.to(), provider);

smsRedisHelper.saveSmsAuthToken(key, smsInfo.code(), SmsPrefix.OAUTH);
Expand All @@ -111,16 +111,29 @@ public SmsRes sendCode(SmsReq dto, Long id, ProviderType provider) {
}

@Transactional
public String checkCertificationNumber(SmsReq req, Long id, String code, ProviderType provider) {
public Jwt checkCertificationNumber(OauthSmsReq req, Long id, String code, ProviderType provider) {
String key = makeTopic(req.to(), provider);
if (!smsRedisHelper.isCorrectCode(key, code, SmsPrefix.OAUTH)) {
log.warn("인증번호 불일치 -> 사용자 입력 인증 번호 : {}", code);
throw new GlobalErrorException(SmsErrorCode.INVALID_AUTH_CODE);
}
smsRedisHelper.removeCode(key, SmsPrefix.OAUTH);
return jwtUtil.generateSmsOauthToken(SmsAuthInfo.of(id, key));

if (memberSearchService.isExistByPhone(req.to())) {
Member member = memberSearchService.findByPhone(req.to());
String idToken = oidcTokenService.findOIDCToken(req.idToken()).getToken();
OIDCDecodePayload payload = getPayload(provider, idToken, req.nonce());
OauthAccount oauthAccount = OauthAccount.of(id, provider, payload.email(), member);

return generateToken(JwtUserInfo.from(member));
}

return Jwt.of(jwtUtil.generateSmsOauthToken(SmsAuthInfo.of(id, key)), null);
}

/**
* idToken을 통해 payload를 가져온다.
*/
private OIDCDecodePayload getPayload(ProviderType provider, String idToken, String nonce) {
OauthClient oauthClient = oauthClientHelper.getOauthClient(provider);
OauthApplicationConfig oauthApplicationConfig = oauthApplicationConfigHelper.getOauthApplicationConfig(provider);
Expand Down

0 comments on commit 6582d32

Please sign in to comment.