Skip to content

Commit

Permalink
Merge pull request #26 from 6QuizOnTheBlock/be/feat/#22-signIn
Browse files Browse the repository at this point in the history
Be/feat/#22 Spring Security 기본 환경 설정
  • Loading branch information
dalcheonroadhead authored Apr 29, 2024
2 parents 0cb82bd + e667610 commit 2bb5b98
Show file tree
Hide file tree
Showing 16 changed files with 761 additions and 7 deletions.
28 changes: 22 additions & 6 deletions backEnd/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,42 @@ repositories {
}

dependencies {

// ⭐ Spring Basic Setting
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

// ⭐ Database
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
runtimeOnly 'com.mysql:mysql-connector-j'

// ⭐ Jasypt
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'

// ⭐ SWAGGER
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// aws
// ⭐ AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//querydsl
// ⭐ QueryDsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

// ⭐ JWT (현: 0.11.5 -> 0.12.3 migration 예정)
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.quiz.ourclass.domain.member.controller;

import com.amazonaws.Response;
import com.quiz.ourclass.domain.member.dto.request.MemberAdditionalInfoRequest;
import com.quiz.ourclass.domain.member.dto.request.MemberSignUpRequest;
import com.quiz.ourclass.domain.member.dto.request.MemberSigninRequest;
import com.quiz.ourclass.domain.member.service.MemberService;
import com.quiz.ourclass.global.dto.ApiResponse;
import com.quiz.ourclass.global.util.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/members")
@RequiredArgsConstructor
public class MemberController {

private final MemberService memberService;

/* 1. 회원가입 */
@PostMapping("/")
public ResponseEntity<ApiResponse<?>> signUp (MemberSignUpRequest request) throws Exception {
return ResponseEntity.ok(ApiResponse.success(memberService.signUpProcess(request)));
}

/* 2. 추가정보 받기 */
@PatchMapping(value = "/", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<ApiResponse<?>> setUpInfo (@AuthenticationPrincipal UserDetailsImpl userDetails,MemberAdditionalInfoRequest request){

memberService.addingInfoProcess(userDetails, request);

return ResponseEntity.ok(ApiResponse.success("추가정보 기입에 성공했습니다."));
}

/* 3. 로그인 */
@PostMapping("/sign-in")
public ResponseEntity<ApiResponse<?>> signIn (MemberSigninRequest request) {

return ResponseEntity.ok(ApiResponse.success(memberService.signInProcess(request)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.quiz.ourclass.domain.member.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class TokenDTO {

private String accessToken;
private String refreshToken;

@Builder
private TokenDTO (String accessToken, String refreshToken){
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}

public static TokenDTO of (String accessToken, String refreshToken){
return TokenDTO.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.quiz.ourclass.domain.member.dto.request;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;

@Getter
@Setter
@Builder
public class MemberAdditionalInfoRequest {
private MultipartFile file;
private String role;


private MemberAdditionalInfoRequest (MultipartFile file, String role){
this.file = file;
this.role = role;
}

public static MemberAdditionalInfoRequest of(MultipartFile file, String role){
return builder().file(file).role(role).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.quiz.ourclass.domain.member.dto.request;

import lombok.Getter;
import lombok.Setter;


@Setter
@Getter
public class MemberSignUpRequest {

String email;
String name;
String socialType;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.quiz.ourclass.domain.member.dto.request;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class MemberSigninRequest {

private String email;


private MemberSigninRequest (String email) {
this.email = email;
}


public static MemberSigninRequest of (String email) {
return builder().email(email).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Member {

@Id
Expand All @@ -20,4 +27,30 @@ public class Member {
SocialType socialType;
@Enumerated(EnumType.STRING)
Role role;

@Builder
private Member (String email, String name, String profileImage, SocialType socialType, Role role){
this.email = email;
this.name = name;
this.profileImage = profileImage;
this.socialType = socialType;
this.role = role;
}


public static Member Guest (String email, String name, SocialType socialType) {
return Member.builder()
.email(email)
.name(name)
.socialType(socialType)
.role(Role.GUEST)
.build();
}

public static Member addInfo (Member member, String profileImage, String role){
member.setProfileImage(profileImage);
member.setRole(role.equals("TEACHER")? Role.TEACHER : Role.STUDENT);

return member;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.quiz.ourclass.domain.member.repository;

import com.quiz.ourclass.domain.member.entity.Member;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findById(Long id);
Optional<Member> findByEmail(String email);

boolean existsByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.quiz.ourclass.domain.member.service;

import com.amazonaws.services.s3.AmazonS3;
import com.quiz.ourclass.domain.member.dto.request.MemberAdditionalInfoRequest;
import com.quiz.ourclass.domain.member.dto.request.MemberSignUpRequest;
import com.quiz.ourclass.domain.member.dto.TokenDTO;
import com.quiz.ourclass.domain.member.dto.request.MemberSigninRequest;
import com.quiz.ourclass.domain.member.entity.Member;
import com.quiz.ourclass.domain.member.entity.Role;
import com.quiz.ourclass.domain.member.entity.SocialType;
import com.quiz.ourclass.domain.member.repository.MemberRepository;
import com.quiz.ourclass.global.exception.ErrorCode;
import com.quiz.ourclass.global.exception.GlobalException;
import com.quiz.ourclass.global.util.AwsS3ObjectStorage;
import com.quiz.ourclass.global.util.UserDetailsImpl;
import com.quiz.ourclass.global.util.jwt.JwtUtil;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class MemberService {

private final MemberRepository memberRepository;
private final JwtUtil jwtUtil;
private final AwsS3ObjectStorage awsS3ObjectStorage;

public TokenDTO signUpProcess (MemberSignUpRequest request) throws Exception{

if(memberRepository.existsByEmail(request.getEmail())){
throw new GlobalException(ErrorCode.EXISTING_MEMBER);
}

else{

Member member = memberRepository.save(Member.Guest(request.getEmail(), request.getName(), checkSocialType(
request.getSocialType())));

String accessToken = jwtUtil.createToken(member, true);
String refreshToken = jwtUtil.createToken(member, false);

return TokenDTO.of(accessToken, refreshToken);
}

}

public void addingInfoProcess (UserDetailsImpl userDetails, MemberAdditionalInfoRequest request)
{
Member member = userDetails.getMember();

try {
member.setProfileImage(awsS3ObjectStorage.uploadFile(request.getFile()));
} catch (IOException e) {
throw new GlobalException(ErrorCode.AWS_SERVER_ERROR);
}
member.setRole(request.getRole().equals("teacher")? Role.TEACHER : Role.STUDENT);
memberRepository.save(member);
}

public TokenDTO signInProcess(MemberSigninRequest request) {
if(!memberRepository.existsByEmail(request.getEmail())){
throw new GlobalException(ErrorCode.NOT_FOUND_MEMBER);
} else {
Member member = memberRepository.findByEmail(request.getEmail()).orElseThrow();
String accessToken = jwtUtil.createToken(member, true);
String refreshToken = jwtUtil.createToken(member, false);

return TokenDTO.of(accessToken, refreshToken);
}
}



private SocialType checkSocialType (String socialType){
return switch (socialType) {
case "kakao", "KAKAO" -> SocialType.KAKAO;
case "google", "GOOGLE" -> SocialType.GOOGLE;
case "naver", "NAVER" -> SocialType.NAVER;
default -> null;
};

}
}
Loading

0 comments on commit 2bb5b98

Please sign in to comment.