Skip to content
Open
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
16 changes: 16 additions & 0 deletions leeseo/umc10th/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ dependencies {
// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.1'

// Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'

// Jwt
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
implementation 'org.springframework.boot:spring-boot-configuration-processor'

// OAuth
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example.umc10th.domain.auth.controller;

import com.example.umc10th.domain.auth.dto.AuthReqDto;
import com.example.umc10th.domain.auth.dto.AuthResDto;
import com.example.umc10th.domain.auth.exception.code.AuthSuccessCode;
import com.example.umc10th.domain.auth.service.AuthService;
import com.example.umc10th.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth")
@Tag(name = "Auth", description = "인증 관련 API")
public class AuthController implements AuthControllerDocs{

private final AuthService authService;

@PostMapping("/sign-up")
public ApiResponse<AuthResDto.Id> signUp(
@RequestBody @Valid AuthReqDto.Signup dto
) {
return ApiResponse.onSuccess(AuthSuccessCode.SIGNUP_OK, authService.signUp(dto));
}

@PostMapping("/login")
public ApiResponse<AuthResDto.AccessToken> login(
@RequestBody @Valid AuthReqDto.Login dto
) {
return ApiResponse.onSuccess(AuthSuccessCode.LOGIN_OK, authService.login(dto));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.umc10th.domain.auth.controller;

import com.example.umc10th.domain.auth.dto.AuthReqDto;
import com.example.umc10th.domain.auth.dto.AuthResDto;
import com.example.umc10th.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.RequestBody;

public interface AuthControllerDocs {

@Operation(
summary = "회원가입",
description = "이메일 회원가입 진행"
)
public ApiResponse<AuthResDto.Id> signUp(
@RequestBody @Valid AuthReqDto.Signup dto
);

@Operation(
summary = "이메일 로그인",
description = "이메일 로그인 진행"
)
public ApiResponse<AuthResDto.AccessToken> login(
@RequestBody @Valid AuthReqDto.Login dto
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.umc10th.domain.auth.converter;

import com.example.umc10th.domain.auth.dto.AuthReqDto;
import com.example.umc10th.domain.auth.dto.AuthResDto;
import com.example.umc10th.domain.member.entity.Member;
import com.example.umc10th.domain.member.enums.SocialType;
import com.example.umc10th.global.security.dto.OAuthDto;

import java.util.UUID;


public class AuthConverter {

public static Member toMember(
AuthReqDto.Signup dto,
String salt
) {
return Member.builder()
.email(dto.email())
.password(salt)
.nickname(dto.nickname())
.gender(dto.gender())
.birth(dto.birth())
.address(dto.address())
.fullAddress(dto.fullAddress())
.socialId("email"+UUID.randomUUID())
.socialType(SocialType.EMAIL)
.build();
}

public static Member toSocialMember(
OAuthDto dto
) {
return Member.builder()
.email(dto.getSocialEmail())
.nickname(dto.getName())
.socialId(dto.getSocialUid())
.socialType(dto.getSocialType())
.build();
}

public static AuthResDto.AccessToken toAccessToken(
String accessToken
) {
return AuthResDto.AccessToken.builder()
.accessToken(accessToken)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.example.umc10th.domain.auth.dto;

import com.example.umc10th.domain.member.dto.MemberReqDto;
import com.example.umc10th.domain.member.enums.FoodType;
import com.example.umc10th.domain.member.enums.Gender;
import com.example.umc10th.domain.mission.enums.Address;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;

import java.time.LocalDate;
import java.util.List;

public class AuthReqDto {

@Schema(name = "SignUp", description = "회원가입 정보를 저장합합니다.")
public record Signup (
@Email
@NotBlank
String email,
@NotBlank
String password,
@NotBlank
String nickname,
@NotNull
Gender gender,
@NotNull
LocalDate birth,
@NotNull
Address address,
@NotBlank
String fullAddress,
@NotNull
List<FoodType> food
) {}

@Schema(name = "Login", description = "로그인 정보를 저장합니다.")
public record Login (
@Email
@NotBlank
String email,
@NotBlank
String password
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.umc10th.domain.auth.dto;

import lombok.Builder;
import lombok.Getter;

@Getter
public class AuthResDto {

@Builder
public record Id(
Long id
) {}

@Builder
public record AccessToken(
String accessToken
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.umc10th.domain.auth.exception;

import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
import com.example.umc10th.global.apiPayload.exception.BaseException;

public class AuthException extends BaseException {
public AuthException(BaseErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.umc10th.domain.auth.exception.code;

import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum AuthErrorCode implements BaseErrorCode {
INVALID_PASSWORD(HttpStatus.BAD_REQUEST,
"AUTH400_1",
"잘못된 비밀번호입니다.");

private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.umc10th.domain.auth.exception.code;

import com.example.umc10th.global.apiPayload.code.BaseSuccessCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum AuthSuccessCode implements BaseSuccessCode {

SIGNUP_OK(HttpStatus.OK,
"AUTH200_1",
"회원가입 되었습니다."),

LOGIN_OK(HttpStatus.OK,
"AUTH200_2",
"로그인 되었습니다.");

private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.example.umc10th.domain.auth.service;

import com.example.umc10th.domain.auth.converter.AuthConverter;
import com.example.umc10th.domain.auth.dto.AuthReqDto;
import com.example.umc10th.domain.auth.dto.AuthResDto;
import com.example.umc10th.domain.auth.exception.AuthException;
import com.example.umc10th.domain.auth.exception.code.AuthErrorCode;
import com.example.umc10th.domain.member.converter.MemberConverter;
import com.example.umc10th.domain.member.entity.Food;
import com.example.umc10th.domain.member.entity.Member;
import com.example.umc10th.domain.member.enums.FoodType;
import com.example.umc10th.domain.member.exception.FoodException;
import com.example.umc10th.domain.member.exception.MemberException;
import com.example.umc10th.domain.member.exception.code.FoodErrorCode;
import com.example.umc10th.domain.member.exception.code.MemberErrorCode;
import com.example.umc10th.domain.member.repository.FoodRepository;
import com.example.umc10th.domain.member.repository.MemberRepository;
import com.example.umc10th.domain.member.service.MemberService;
import com.example.umc10th.global.security.entity.AuthMember;
import com.example.umc10th.global.security.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class AuthService {

private final FoodRepository foodRepository;
private final PasswordEncoder passwordEncoder;
private final MemberRepository memberRepository;
private final JwtUtil jwtUtil;

@Transactional
public AuthResDto.Id signUp(AuthReqDto.Signup dto) {
String salt = passwordEncoder.encode(dto.password());
Member member = AuthConverter.toMember(dto, salt);
List<Food> list = new ArrayList<>();
if (dto.food() != null) {
for (FoodType f : dto.food()) {
Food food = foodRepository.findByName(f)
.orElseThrow(() -> new FoodException(FoodErrorCode.FOOD_TYPE_NOT_FOUND));
list.add(food);
}
}
memberRepository.save(member);
member.updateFoodList(list);
return AuthResDto.Id.builder().id(member.getId()).build();
}

public AuthResDto.AccessToken login(AuthReqDto.Login dto) {
Member member = memberRepository.findByEmail(dto.email())
.orElseThrow(() -> new MemberException(MemberErrorCode.MEMBER_NOT_FOUND));

if (!passwordEncoder.matches(dto.password(), member.getPassword())) {
throw new AuthException(AuthErrorCode.INVALID_PASSWORD);
}

AuthMember authMember = new AuthMember(member);
String accessToken = jwtUtil.createAccessToken(authMember);

return AuthConverter.toAccessToken(accessToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

import com.example.umc10th.domain.member.dto.MemberReqDto;
import com.example.umc10th.domain.member.dto.MemberResDto;
import com.example.umc10th.domain.member.exception.code.MemberErrorCode;
import com.example.umc10th.domain.member.exception.code.MemberSuccessCode;
import com.example.umc10th.domain.member.service.MemberService;
import com.example.umc10th.global.apiPayload.ApiResponse;
import com.example.umc10th.global.security.entity.AuthMember;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/vi/members")
@RequestMapping("/api/v1/members")
@Tag(name = "Member", description = "회원 관련 API")
public class MemberController implements MemberControllerDocs{

Expand All @@ -27,24 +29,32 @@ public ApiResponse<Void> saveTermAgreement(
}

@GetMapping("/me/profile")
public ApiResponse<MemberResDto.Profile> getMyProfile(
@AuthenticationPrincipal AuthMember member
) {
MemberResDto.Profile response = memberService.getMyProfile(member.getMember());
return ApiResponse.onSuccess(MemberSuccessCode.PROFILE_GET_OK, response);
}

@GetMapping("/{id}/profile")
public ApiResponse<MemberResDto.Profile> getProfile(
@RequestParam Long id
@PathVariable Long id
) {
MemberResDto.Profile response = memberService.getProfile(id);
return ApiResponse.onSuccess(MemberSuccessCode.PROFILE_GET_OK, response);
}

@PatchMapping("/me/profile")
public ApiResponse<Void> updateProfile(
@RequestBody MemberReqDto.Profile dto
@RequestBody @Valid MemberReqDto.Profile dto
) {
memberService.updateProfile(dto);
return ApiResponse.onSuccess(MemberSuccessCode.PROFILE_PATCH_OK, null);
}

@PatchMapping("/me/nickname")
public ApiResponse<Void> updateNickname(
@RequestBody MemberReqDto.Nickname dto
@RequestBody @Valid MemberReqDto.Nickname dto
) {
memberService.updateNickname(dto);
return ApiResponse.onSuccess(MemberSuccessCode.NICKNAME_PATCH_OK, null);
Expand Down
Loading