Skip to content
Merged
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
@@ -1,11 +1,13 @@
package com.example.solidconnection.auth.controller;

import com.example.solidconnection.auth.dto.KakaoCodeDto;
import com.example.solidconnection.auth.dto.KakaoOauthResponseDto;
import com.example.solidconnection.auth.dto.SignUpRequestDto;
import com.example.solidconnection.auth.dto.kakao.KakaoCodeDto;
import com.example.solidconnection.auth.dto.kakao.KakaoOauthResponseDto;
import com.example.solidconnection.auth.service.AuthService;
import com.example.solidconnection.auth.service.KakaoOAuthService;
import com.example.solidconnection.custom.exception.CustomException;
import com.example.solidconnection.custom.response.CustomResponse;
import com.example.solidconnection.custom.response.DataResponse;
import com.example.solidconnection.custom.response.StatusResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -17,11 +19,17 @@
@RequiredArgsConstructor
public class AuthController {
private final KakaoOAuthService kakaoOAuthService;
private final AuthService authService;

@PostMapping("/kakao")
public CustomResponse kakaoOauth(@RequestBody KakaoCodeDto kakaoCodeDto) throws CustomException {
public CustomResponse kakaoOauth(@RequestBody KakaoCodeDto kakaoCodeDto) {
KakaoOauthResponseDto kakaoOauthResponseDto = kakaoOAuthService.processOauth(kakaoCodeDto.getCode());
return new DataResponse<>(kakaoOauthResponseDto);
}

@PostMapping("/sign-up")
public CustomResponse signUp(@RequestBody SignUpRequestDto signUpRequestDto) {
boolean status = authService.signUp(signUpRequestDto);
return new StatusResponse(status);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.solidconnection.auth.dto;

import com.example.solidconnection.auth.dto.kakao.KakaoOauthResponseDto;
import lombok.*;

@Getter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.solidconnection.auth.dto;

import com.example.solidconnection.type.Gender;
import com.example.solidconnection.type.PreparationStatus;
import lombok.*;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SignUpRequestDto {
private String kakaoOauthToken;
private List<String> interestedRegions;
private List<String> interestedCountries;
private PreparationStatus preparationStatus;
private String nickname;
private String profileImageUrl;
private Gender gender;
private String birth;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import lombok.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.example.solidconnection.auth.dto.kakao;

public class KakaoOauthResponseDto {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.solidconnection.auth.dto;
package com.example.solidconnection.auth.dto.kakao;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.example.solidconnection.auth.service;


import com.example.solidconnection.auth.dto.SignUpRequestDto;
import com.example.solidconnection.config.token.TokenService;
import com.example.solidconnection.config.token.TokenValidator;
import com.example.solidconnection.country.CountryRepository;
import com.example.solidconnection.country.InterestedCountyRepository;
import com.example.solidconnection.custom.exception.CustomException;
import com.example.solidconnection.entity.*;
import com.example.solidconnection.region.InterestedRegionRepository;
import com.example.solidconnection.region.RegionRepository;
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
import com.example.solidconnection.type.CountryCode;
import com.example.solidconnection.type.RegionCode;
import com.example.solidconnection.type.Role;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.stream.Collectors;

import static com.example.solidconnection.custom.exception.ErrorCode.*;

@Service
@RequiredArgsConstructor
public class AuthService {
private final TokenValidator tokenValidator;
private final TokenService tokenService;
private final SiteUserRepository siteUserRepository;
private final RegionRepository regionRepository;
private final InterestedRegionRepository interestedRegionRepository;
private final CountryRepository countryRepository;
private final InterestedCountyRepository interestedCountyRepository;

public boolean signUp(SignUpRequestDto signUpRequestDto) {
tokenValidator.validateKakaoToken(signUpRequestDto.getKakaoOauthToken());
validateUserNotDuplicated(signUpRequestDto);
validateNicknameDuplicated(signUpRequestDto.getNickname());
validateBirthFormat(signUpRequestDto.getBirth());

SiteUser siteUser = makeSiteUserEntity(signUpRequestDto);
SiteUser savedSiteUser = siteUserRepository.save(siteUser);

saveInterestedRegion(signUpRequestDto, savedSiteUser);
saveInterestedCountry(signUpRequestDto, savedSiteUser);
return true;
}

private void validateUserNotDuplicated(SignUpRequestDto signUpRequestDto){
String email = tokenService.getEmail(signUpRequestDto.getKakaoOauthToken());
if(siteUserRepository.existsByEmail(email)){
throw new CustomException(USER_ALREADY_EXISTED);
}
}

private void validateNicknameDuplicated(String nickname){
if(siteUserRepository.existsByNickname(nickname)){
throw new CustomException(NICKNAME_ALREADY_EXISTED);
}
}

private void validateBirthFormat(String birthInput) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try {
LocalDate.parse(birthInput, formatter);
} catch (DateTimeParseException e) {
throw new CustomException(INVALID_BIRTH_FORMAT);
}
}

private SiteUser makeSiteUserEntity(SignUpRequestDto signUpRequestDto) {
return SiteUser.builder()
.email(tokenService.getEmail(signUpRequestDto.getKakaoOauthToken()))
.nickname(signUpRequestDto.getNickname())
.preparationStage(signUpRequestDto.getPreparationStatus())
.profileImageUrl(signUpRequestDto.getProfileImageUrl())
.gender(signUpRequestDto.getGender())
.birth(signUpRequestDto.getBirth())
.role(Role.MENTEE)
.build();
}

private void saveInterestedCountry(SignUpRequestDto signUpRequestDto, SiteUser savedSiteUser) {
List<InterestedCountry> interestedCountries = signUpRequestDto.getInterestedCountries().stream()
.map(CountryCode::getCountryCodeByKoreanName)
.map(countryCode -> {
Country country = countryRepository.findByCountryCode(countryCode)
.orElseThrow(() -> new RuntimeException("Country Code enum이랑 table이랑 다름 : " + countryCode.name()));
return InterestedCountry.builder()
.siteUser(savedSiteUser)
.country(country)
.build();
})
.collect(Collectors.toList());
interestedCountyRepository.saveAll(interestedCountries);
}

private void saveInterestedRegion(SignUpRequestDto signUpRequestDto, SiteUser savedSiteUser) {
List<InterestedRegion> interestedRegions = signUpRequestDto.getInterestedRegions().stream()
.map(RegionCode::getRegionCodeByKoreanName)
.map(regionCode -> {
Region region = regionRepository.findByRegionCode(regionCode)
.orElseThrow(() -> new RuntimeException("Region Code enum이랑 table이랑 다름 : " + regionCode.name()));
return InterestedRegion.builder()
.siteUser(savedSiteUser)
.region(region)
.build();
})
.collect(Collectors.toList());
interestedRegionRepository.saveAll(interestedRegions);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.solidconnection.auth.service;

import com.example.solidconnection.auth.dto.*;
import com.example.solidconnection.auth.dto.SignInResponseDto;
import com.example.solidconnection.auth.dto.kakao.*;
import com.example.solidconnection.config.token.TokenService;
import com.example.solidconnection.config.token.TokenType;
import com.example.solidconnection.custom.exception.CustomException;
Expand Down Expand Up @@ -56,7 +57,7 @@ private String getKakaoAccessToken(String code) {
);
return Objects.requireNonNull(response.getBody()).getAccessToken();
} catch (Exception e){
throw new CustomException(KAKAO_AUTH_CODE_FAIL);
throw new CustomException(INVALID_KAKAO_AUTH_CODE);
}
}

Expand Down Expand Up @@ -93,8 +94,9 @@ private KakaoUserInfoDto getKakaoUserInfo(String accessToken) {
}

private SignInResponseDto kakaoSignIn(String email) {
var accessToken = tokenService.generateToken(email, TokenType.ACCESS);
var refreshToken = tokenService.saveToken(email, TokenType.REFRESH);
String accessToken = tokenService.generateToken(email, TokenType.ACCESS);
String refreshToken = tokenService.generateToken(email, TokenType.REFRESH);
tokenService.saveToken(refreshToken, TokenType.REFRESH);
return SignInResponseDto.builder()
.registered(true)
.accessToken(accessToken)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.solidconnection.config.security;

import com.example.solidconnection.custom.exception.CustomException;
import com.example.solidconnection.custom.response.ErrorResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -23,7 +22,7 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
ErrorResponse errorResponse = new ErrorResponse(new CustomException(AUTHENTICATION_FAILED, authException.getMessage()));
ErrorResponse errorResponse = new ErrorResponse(AUTHENTICATION_FAILED, authException.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ public class TokenService {

public String generateToken(String email, TokenType tokenType) {
Claims claims = Jwts.claims().setSubject(email);

var now = new Date();
var expiredDate = new Date(now.getTime() + tokenType.getExpireTime());

Date now = new Date();
Date expiredDate = new Date(now.getTime() + tokenType.getExpireTime());
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
Expand All @@ -41,16 +39,13 @@ public String generateToken(String email, TokenType tokenType) {
.compact();
}

public String saveToken(String email, TokenType tokenType) {
String token = generateToken(email, tokenType);

public void saveToken(String token, TokenType tokenType) {
redisTemplate.opsForValue().set(
tokenType.getPrefix() + email,
tokenType.getPrefix() + getClaim(token).getSubject(),
token,
tokenType.getExpireTime(),
TimeUnit.MILLISECONDS
);
return token;
}

public Authentication getAuthentication(String token) {
Expand All @@ -60,6 +55,10 @@ public Authentication getAuthentication(String token) {
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}

public String getEmail(String token) {
return getClaim(token).getSubject();
}

private Claims getClaim(String token) {
return Jwts.parser()
.setSigningKey(this.secretKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.Objects;

import static com.example.solidconnection.custom.exception.ErrorCode.*;

Expand All @@ -23,7 +24,7 @@ public class TokenValidator {

public void validateAccessToken(String token) {
validateTokenNotEmpty(token);
validateAccessTokenNotExpired(token);
validateTokenNotExpired(token, TokenType.ACCESS);
validateRefreshToken(token);
// TODO : validateNotLogOut 함수 생성 및 추가
}
Expand All @@ -35,11 +36,29 @@ private void validateRefreshToken(String token) {
}
}

private void validateAccessTokenNotExpired(String token) {
public void validateKakaoToken(String token) {
validateTokenNotEmpty(token);
validateTokenNotExpired(token, TokenType.KAKAO_OAUTH);
validateKakaoTokenNotUsed(token);
}

private void validateKakaoTokenNotUsed(String token) {
String email = getClaim(token).getSubject();
if (Objects.equals(redisTemplate.opsForValue().get(TokenType.KAKAO_OAUTH.getPrefix() + email), token)) {
throw new CustomException(INVALID_KAKAO_TOKEN);
}
}

private void validateTokenNotExpired(String token, TokenType tokenType) {
Date expiration = getClaim(token).getExpiration();
long now = new Date().getTime();
if((expiration.getTime() - now) < 0){
throw new CustomException(ACCESS_TOKEN_EXPIRED);
if ((expiration.getTime() - now) < 0) {
if (tokenType.equals(TokenType.ACCESS)) {
throw new CustomException(ACCESS_TOKEN_EXPIRED);
}
if (token.equals(TokenType.KAKAO_OAUTH)) {
throw new CustomException(INVALID_KAKAO_TOKEN);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.solidconnection.country;

import com.example.solidconnection.entity.Country;
import com.example.solidconnection.type.CountryCode;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface CountryRepository extends JpaRepository<Country, Long> {
Optional<Country> findByCountryCode(CountryCode countryCode);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.solidconnection.country;

import com.example.solidconnection.entity.InterestedCountry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface InterestedCountyRepository extends JpaRepository<InterestedCountry, Long> {
List<InterestedCountry> findAllBySiteUser_Email(String email);
}
Loading