Skip to content

Commit

Permalink
[FEAT]: 사장 Authorization 구현 (#141)
Browse files Browse the repository at this point in the history
* feat: 사장 로그아웃 기능 구현

* feat: 사장 탈퇴 기능 구현

* fix: 유저 로그인 유저 검증 추가
  • Loading branch information
sejineer authored Nov 6, 2023
1 parent e137253 commit cdceaee
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 26 deletions.
54 changes: 28 additions & 26 deletions src/main/java/com/shallwe/domain/auth/application/AuthService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.shallwe.domain.auth.application;

import java.net.URI;
import java.util.Optional;

import com.shallwe.domain.auth.dto.*;
Expand All @@ -10,36 +9,33 @@
import com.shallwe.domain.shopowner.domain.repository.ShopOwnerRepository;
import com.shallwe.domain.shopowner.exception.AlreadyExistPhoneNumberException;
import com.shallwe.domain.shopowner.exception.InvalidPhoneNumberException;
import com.shallwe.domain.user.exception.InvalidUserException;
import com.shallwe.global.DefaultAssert;
import com.shallwe.global.config.security.token.UserPrincipal;

import com.shallwe.domain.user.domain.Provider;
import com.shallwe.domain.user.domain.Role;
import com.shallwe.domain.auth.domain.Token;
import com.shallwe.domain.user.domain.User;
import com.shallwe.global.error.DefaultAuthenticationException;
import com.shallwe.global.payload.ApiResponse;
import com.shallwe.global.payload.ErrorCode;
import com.shallwe.global.payload.Message;
import com.shallwe.domain.auth.domain.repository.TokenRepository;
import com.shallwe.domain.user.domain.repository.UserRepository;

import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import lombok.RequiredArgsConstructor;


@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class AuthService {

private final CustomTokenProviderService customTokenProviderService;
Expand Down Expand Up @@ -91,6 +87,12 @@ public AuthRes signUp(final SignUpReq signUpReq) {

@Transactional
public AuthRes signIn(final SignInReq signInReq) {
User user = userRepository.findByEmail(signInReq.getEmail())
.orElseThrow(InvalidUserException::new);
if (!user.getProviderId().equals(signInReq.getProviderId())) {
throw new InvalidPasswordException();
}

Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
signInReq.getEmail(),
Expand All @@ -113,6 +115,7 @@ public AuthRes signIn(final SignInReq signInReq) {
.build();
}

@Transactional
public AuthRes refresh(final RefreshTokenReq tokenRefreshRequest) {
//1차 검증
boolean checkValid = valid(tokenRefreshRequest.getRefreshToken());
Expand Down Expand Up @@ -141,11 +144,8 @@ public AuthRes refresh(final RefreshTokenReq tokenRefreshRequest) {
return authResponse;
}

@Transactional
public Message signOut(final RefreshTokenReq tokenRefreshRequest) {
boolean checkValid = valid(tokenRefreshRequest.getRefreshToken());
DefaultAssert.isAuthentication(checkValid);

//4 token 정보를 삭제한다.
Token token = tokenRepository.findByRefreshToken(tokenRefreshRequest.getRefreshToken())
.orElseThrow(() -> new DefaultAuthenticationException(ErrorCode.INVALID_AUTHENTICATION));
tokenRepository.delete(token);
Expand All @@ -155,22 +155,7 @@ public Message signOut(final RefreshTokenReq tokenRefreshRequest) {
.build();
}

private boolean valid(final String refreshToken) {
//1. 토큰 형식 물리적 검증
boolean validateCheck = customTokenProviderService.validateToken(refreshToken);
DefaultAssert.isTrue(validateCheck, "Token 검증에 실패하였습니다.");

//2. refresh token 값을 불러온다.
Optional<Token> token = tokenRepository.findByRefreshToken(refreshToken);
DefaultAssert.isTrue(token.isPresent(), "탈퇴 처리된 회원입니다.");

//3. email 값을 통해 인증값을 불러온다
Authentication authentication = customTokenProviderService.getAuthenticationByEmail(token.get().getUserEmail());
DefaultAssert.isTrue(token.get().getUserEmail().equals(authentication.getName()), "사용자 인증에 실패하였습니다.");

return true;
}

@Transactional
public AuthRes shopOwnerSignUp(final ShopOwnerSignUpReq shopOwnerSignUpReq) {
if (shopOwnerRepository.existsByPhoneNumber(shopOwnerSignUpReq.getPhoneNumber())) {
throw new AlreadyExistPhoneNumberException();
Expand Down Expand Up @@ -208,6 +193,7 @@ public AuthRes shopOwnerSignUp(final ShopOwnerSignUpReq shopOwnerSignUpReq) {
return authRes;
}

@Transactional
public AuthRes shopOwnerSignIn(final ShopOwnerSignInReq shopOwnerSignInReq) {
ShopOwner shopOwner = shopOwnerRepository.findShopOwnerByPhoneNumber(shopOwnerSignInReq.getPhoneNumber())
.orElseThrow(InvalidPhoneNumberException::new);
Expand Down Expand Up @@ -239,4 +225,20 @@ public AuthRes shopOwnerSignIn(final ShopOwnerSignInReq shopOwnerSignInReq) {
return authRes;
}

private boolean valid(final String refreshToken) {
//1. 토큰 형식 물리적 검증
boolean validateCheck = customTokenProviderService.validateToken(refreshToken);
DefaultAssert.isTrue(validateCheck, "Token 검증에 실패하였습니다.");

//2. refresh token 값을 불러온다.
Optional<Token> token = tokenRepository.findByRefreshToken(refreshToken);
DefaultAssert.isTrue(token.isPresent(), "탈퇴 처리된 회원입니다.");

//3. email 값을 통해 인증값을 불러온다
Authentication authentication = customTokenProviderService.getAuthenticationByEmail(token.get().getUserEmail());
DefaultAssert.isTrue(token.get().getUserEmail().equals(authentication.getName()), "사용자 인증에 실패하였습니다.");

return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,17 @@ public ResponseCustom<AuthRes> shopOwnerSignIn(
return ResponseCustom.OK(authService.shopOwnerSignIn(shopOwnerSignInReq));
}

@Operation(summary = "사장 로그아웃", description = "사장 로그아웃을 수행합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "사장 로그아웃 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = Message.class) ) } ),
@ApiResponse(responseCode = "400", description = "사장 로그아웃 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
})
@PostMapping(value="/shop-owner/sign-out")
public ResponseCustom<Message> shopOwnerSignOut(
@Parameter(description = "Accesstoken을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal,
@Parameter(description = "Schemas의 RefreshTokenRequest를 참고해주세요.", required = true) @Valid @RequestBody RefreshTokenReq tokenRefreshRequest
) {
return ResponseCustom.OK(authService.signOut(tokenRefreshRequest));
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
package com.shallwe.domain.shopowner.application;

import com.shallwe.domain.shopowner.dto.ShopOwnerChangePasswordReq;
import com.shallwe.domain.user.dto.DeleteUserRes;
import com.shallwe.global.config.security.token.UserPrincipal;
import com.shallwe.global.payload.Message;

public interface ShopOwnerService {

Message shopOwnerChangePassword(UserPrincipal userPrincipal, ShopOwnerChangePasswordReq shopOwnerChangePasswordReq);
Message deleteCurrentShopOwner(UserPrincipal userPrincipal);

}

Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.shallwe.domain.shopowner.application;


import com.shallwe.domain.auth.domain.Token;
import com.shallwe.domain.auth.domain.repository.TokenRepository;
import com.shallwe.domain.common.Status;
import com.shallwe.domain.shopowner.domain.ShopOwner;
import com.shallwe.domain.shopowner.domain.repository.ShopOwnerRepository;
import com.shallwe.domain.shopowner.dto.ShopOwnerChangePasswordReq;
import com.shallwe.domain.shopowner.exception.InvalidShopOwnerException;
import com.shallwe.domain.user.domain.User;
import com.shallwe.domain.user.exception.InvalidTokenException;
import com.shallwe.global.config.security.token.UserPrincipal;
import com.shallwe.global.payload.Message;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,7 +24,9 @@ public class ShopOwnerServiceImpl implements ShopOwnerService {

private final PasswordEncoder passwordEncoder;
private final ShopOwnerRepository shopOwnerRepository;
private final TokenRepository tokenRepository;

@Override
@Transactional
public Message shopOwnerChangePassword(final UserPrincipal userPrincipal, final ShopOwnerChangePasswordReq shopOwnerChangePasswordReq) {
ShopOwner shopOwner = shopOwnerRepository.findById(userPrincipal.getId())
Expand All @@ -31,4 +38,20 @@ public Message shopOwnerChangePassword(final UserPrincipal userPrincipal, final
.message("비밀번호가 변경되었습니다.").build();
}

@Override
@Transactional
public Message deleteCurrentShopOwner(UserPrincipal userPrincipal) {
ShopOwner shopOwner = shopOwnerRepository.findById(userPrincipal.getId())
.orElseThrow(InvalidShopOwnerException::new);
Token token = tokenRepository.findByUserEmail(userPrincipal.getEmail())
.orElseThrow(InvalidTokenException::new);

shopOwner.updateStatus(Status.DELETE);
tokenRepository.delete(token);

return Message.builder()
.message("사장 탈퇴가 완료되었습니다.")
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.shallwe.domain.shopowner.application.ShopOwnerServiceImpl;
import com.shallwe.domain.shopowner.dto.ShopOwnerChangePasswordReq;
import com.shallwe.domain.user.dto.DeleteUserRes;
import com.shallwe.global.config.security.token.CurrentUser;
import com.shallwe.global.config.security.token.UserPrincipal;
import com.shallwe.global.payload.ErrorResponse;
Expand Down Expand Up @@ -39,4 +40,16 @@ public ResponseCustom<Message> shopOwnerChangePassword(
return ResponseCustom.OK(shopOwnerService.shopOwnerChangePassword(userPrincipal, shopOwnerChangePasswordReq));
}

@Operation(summary = "사장 탈퇴", description = "사장 탈퇴를 수행합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "사장 탈퇴 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))}),
@ApiResponse(responseCode = "400", description = "사장 탈퇴 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
@PatchMapping
public ResponseCustom<Message> deleteCurrentShopOwner(
@Parameter(description = "AccessToken 을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal
) {
return ResponseCustom.OK(shopOwnerService.deleteCurrentShopOwner(userPrincipal));
}

}

0 comments on commit cdceaee

Please sign in to comment.