Skip to content

Commit

Permalink
Merge pull request #61 from tukcomCD2024/test#59/feature-backend-tests
Browse files Browse the repository at this point in the history
Test#59/feature backend tests
  • Loading branch information
JunRain2 authored Apr 7, 2024
2 parents c80f62a + b278eb9 commit 3d78fc2
Show file tree
Hide file tree
Showing 13 changed files with 360 additions and 55 deletions.
5 changes: 5 additions & 0 deletions backend/memetory/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ dependencies {

// Swagger 적용
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// test에 lombok 추가
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
package com.example.memetory.domain.member.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.memetory.domain.member.dto.MemberSignUpRequest;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import jakarta.servlet.http.HttpServletResponse;

@Tag(name = "Member")
public interface MemberApi {

@Operation(
summary = "회원가입",
description = "첫 소셜로그인 후 추가 정보 기입",
security = {@SecurityRequirement(name = "access_token")}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "회원가입 성공!"
)
})
ResponseEntity<HttpStatus> register(
MemberSignUpRequest memberSignUpRequest,
@Parameter(hidden = true) String email
);
@Operation(
summary = "회원가입",
description = "첫 소셜로그인 후 추가 정보 기입",
security = {@SecurityRequirement(name = "access_token")}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "회원가입 성공!"
)
})
ResponseEntity<HttpStatus> register(
HttpServletResponse response,
MemberSignUpRequest memberSignUpRequest,
@Parameter(hidden = true) String email
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,32 @@
import com.example.memetory.domain.member.dto.MemberSignUpRequest;
import com.example.memetory.domain.member.service.MemberService;
import com.example.memetory.global.annotation.LoginMemberEmail;
import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService;
import com.example.memetory.global.security.jwt.service.JwtService;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
public class MemberController implements MemberApi {
private final MemberService memberService;
private final JwtService jwtService;
private final RefreshTokenService refreshTokenService;

private final MemberService memberService;
@PostMapping("/sign-up")
@Override
public ResponseEntity<HttpStatus> register(
HttpServletResponse response, @RequestBody MemberSignUpRequest memberSignUpRequest,
@LoginMemberEmail String email) {
MemberServiceDto memberServiceDto = memberSignUpRequest.toServiceDto(email);

@PostMapping("/sign-up")
@Override
public ResponseEntity<HttpStatus> register(@RequestBody MemberSignUpRequest memberSignUpRequest,
@LoginMemberEmail String email) {
MemberServiceDto memberServiceDto = memberSignUpRequest.toServiceDto(email);
memberService.register(memberServiceDto);

memberService.register(memberServiceDto);
String refreshToken = jwtService.createRefreshToken();
jwtService.setRefreshTokenHeader(response, refreshToken);
refreshTokenService.updateToken(email, refreshToken);

return ResponseEntity.status(HttpStatus.OK).build();
}
return ResponseEntity.status(HttpStatus.OK).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
@Schema(description = "회원 가입 포맷")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,24 @@
import org.springframework.transaction.annotation.Transactional;

import com.example.memetory.domain.member.dto.MemberServiceDto;
import com.example.memetory.domain.member.dto.MemberSignUpRequest;
import com.example.memetory.domain.member.entity.Member;
import com.example.memetory.domain.member.exception.NotFoundMemberException;
import com.example.memetory.domain.member.repository.MemberRepository;
import com.example.memetory.global.security.jwt.exception.NotFoundEmailException;
import com.example.memetory.global.security.jwt.exception.NotFoundTokenException;
import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService;
import com.example.memetory.global.security.jwt.service.JwtService;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@RequiredArgsConstructor
@Slf4j
public class MemberService {

private final MemberRepository memberRepository;
private final JwtService jwtService;
private final RefreshTokenService refreshTokenService;
private final HttpServletRequest request;
private final HttpServletResponse response;

@Transactional
public void register(MemberServiceDto memberServiceDto) {
Member member = findByEmail(memberServiceDto.getEmail());

member.register(memberServiceDto);

String refreshToken = jwtService.createRefreshToken();

jwtService.setRefreshTokenHeader(response, refreshToken);
refreshTokenService.updateToken(member.getEmail(), refreshToken);
}

public String getMemberByEmail() {
String accessToken = jwtService.extractAccessToken(request).orElseThrow(NotFoundTokenException::new);
return jwtService.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new);
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.example.memetory.domain.member.service.MemberService;
import com.example.memetory.global.annotation.LoginMemberEmail;
import com.example.memetory.global.security.jwt.service.JwtService;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -18,16 +19,18 @@
@Slf4j
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

private final MemberService memberService;
private final JwtService jwtService;

@Override

public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(LoginMemberEmail.class);
}

@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
return memberService.getMemberByEmail();
HttpServletRequest request = (HttpServletRequest)nativeWebRequest.getNativeRequest();
return jwtService.getEmail(request);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.memetory.domain.member.repository.MemberRepository;
import com.example.memetory.global.security.jwt.refresh.domain.RefreshToken;
import com.example.memetory.global.security.jwt.refresh.repository.RefreshTokenRepository;
import com.example.memetory.global.security.jwt.exception.NotFoundEmailException;
import com.example.memetory.global.security.jwt.exception.NotFoundTokenException;
import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService;

import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -15,7 +15,6 @@

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Optional;
Expand Down Expand Up @@ -112,6 +111,11 @@ public Optional<String> extractEmail(String accessToken) {
}
}

public String getEmail(HttpServletRequest request) {
String accessToken = this.extractAccessToken(request).orElseThrow(NotFoundTokenException::new);
return this.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new);
}

// 헤더에 accessToken 설정
public void setAccessTokenHeader(HttpServletResponse response, String accessToken) {
response.setHeader(accessHeader,BEARER + accessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
if (oAuth2User.getRole() == Role.GUEST) {
String accessToken = jwtService.createAccessToken(oAuth2User.getEmail());
response.addHeader(jwtService.getAccessHeader(), "Bearer " + accessToken);
// response.sendRedirect("oauth2/sign-up"); // 프론트의 회원가입 추가 정보 입력 폼으로 리다이렉트
// response.sendRedirect("/sign-up"); // 프론트의 회원가입 추가 정보 입력 폼으로 리다이렉트

jwtService.setAccessTokenHeader(response, accessToken);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.example.memetory.config;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;

import com.example.memetory.domain.member.repository.MemberRepository;
import com.example.memetory.global.security.jwt.filter.JwtAuthenticationProcessingFilter;
import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService;
import com.example.memetory.global.security.jwt.service.JwtService;

import lombok.RequiredArgsConstructor;

@TestConfiguration
@RequiredArgsConstructor
public class SecurityTestConfig {
private final JwtService jwtService;
private final MemberRepository memberRepository;
private final RefreshTokenService refreshTokenService;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.formLogin(AbstractHttpConfigurer::disable) // 기본 제공하는 로그인 Form 사용 X
.httpBasic(AbstractHttpConfigurer::disable) // Bearer방식이기 때문에 httpBasic 사용 X
.csrf(AbstractHttpConfigurer::disable) //csrf 보안 사용 X
.sessionManagement((sessionManagement) -> // 세션은 사용하지 않기 때문에 stateless 설정
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorizeRequests // 개발을 진행하기 위해 일단 모든 url 허용
-> authorizeRequests.anyRequest().permitAll());

http.addFilterAfter(jwtAuthenticationProcessingFilter(), LogoutFilter.class);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

@Bean
public JwtAuthenticationProcessingFilter jwtAuthenticationProcessingFilter() {
return new JwtAuthenticationProcessingFilter(jwtService, memberRepository, refreshTokenService);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.example.memetory.domain.member;

import com.example.memetory.domain.member.dto.MemberServiceDto;
import com.example.memetory.domain.member.entity.Member;
import com.example.memetory.domain.member.entity.Role;
import com.example.memetory.domain.member.entity.SocialType;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class MemberFixture {
public final static Member MEMBER = Member.builder()
.email("[email protected]")
.role(Role.USER)
.imageUrl("imageUrl")
.nickname("이준우")
.socialType(SocialType.GOOGLE)
.socialId("-1")
.build();

public final static Member GUEST_MEMBER = Member.builder()
.email("[email protected]")
.role(Role.GUEST)
.imageUrl("imageUrl")
.nickname("이준우")
.socialType(SocialType.GOOGLE)
.socialId("-1")
.build();

public final static MemberServiceDto MEMBER_SERVICE_DTO = MemberServiceDto.builder()
.imageUrl("imageUrl")
.nickname("junRain")
.email("[email protected]")
.build();
}
Loading

0 comments on commit 3d78fc2

Please sign in to comment.