Skip to content

Commit

Permalink
Merge pull request #53 from dnd-side-project/develop
Browse files Browse the repository at this point in the history
Deploy/Security & 일정
  • Loading branch information
f1v3-dev authored Aug 7, 2024
2 parents ab22719 + 11738dd commit d7478c0
Show file tree
Hide file tree
Showing 45 changed files with 1,388 additions and 1,847 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ dependencies {
// Spring REST Docs
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'

// test lombok
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
Expand Down
19 changes: 8 additions & 11 deletions src/docs/asciidoc/api/category.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,30 @@
=== 카테고리 목록 조회

.HTTP Request
include::{snippets}/category/getCategoryList/success/http-request.adoc[]
include::{snippets}/category-controller-test/get_list/http-request.adoc[]

.HTTP Response
include::{snippets}/category/getCategoryList/success/http-response.adoc[]
include::{snippets}/category-controller-test/get_list/http-response.adoc[]

.Response Fields
include::{snippets}/category/getCategoryList/success/response-fields.adoc[]
include::{snippets}/category-controller-test/get_list/response-fields.adoc[]

=== 카테고리 개별 조회 - 성공

include::{snippets}/category/getCategory/success/path-parameters.adoc[]
include::{snippets}/category-controller-test/get_success/path-parameters.adoc[]

.HTTP Request
include::{snippets}/category/getCategory/success/http-request.adoc[]
include::{snippets}/category-controller-test/get_success/http-request.adoc[]


.HTTP Response
include::{snippets}/category/getCategory/success/http-response.adoc[]
include::{snippets}/category/getCategory/success/response-fields.adoc[]
include::{snippets}/category-controller-test/get_success/http-response.adoc[]

=== 카테고리 개별 조회 - 실패

.HTTP Request
include::{snippets}/category/getCategory/fail-404/http-request.adoc[]
include::{snippets}/category-controller-test/get_fail/http-request.adoc[]

.HTTP Response
include::{snippets}/category/getCategory/fail-404/http-response.adoc[]
include::{snippets}/category-controller-test/get_fail/http-response.adoc[]

.Error Response
include::{snippets}/category/getCategory/fail-404/response-fields.adoc[]
81 changes: 19 additions & 62 deletions src/docs/asciidoc/api/meeting.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,95 +3,52 @@
=== 모임 생성 - 성공

.HTTP Request
include::{snippets}/meeting/create/success/http-request.adoc[]
include::{snippets}/meeting-controller-test/create_success/http-request.adoc[]

.Request Fields
include::{snippets}/meeting/create/success/request-fields.adoc[]
include::{snippets}/meeting-controller-test/create_success/request-fields.adoc[]

.HTTP Response
include::{snippets}/meeting/create/success/http-response.adoc[]
include::{snippets}/meeting-controller-test/create_success/http-response.adoc[]

=== 모임 생성 - 실패

.HTTP Request
include::{snippets}/meeting/create/fail/http-request.adoc[]
include::{snippets}/meeting-controller-test/create_fail_invalid/http-request.adoc[]

.HTTP Response
include::{snippets}/meeting/create/fail/http-response.adoc[]
include::{snippets}/meeting-controller-test/create_fail_invalid/http-response.adoc[]

.Error Response
include::{snippets}/meeting/create/fail/response-fields.adoc[]
include::{snippets}/meeting-controller-test/create_fail_invalid/response-fields.adoc[]

=== 모임 전체 조회
=== 모임 조회 (UUID)

.Response Fields
include::{snippets}/meeting/getList/success/response-fields.adoc[]
include::{snippets}/meeting-controller-test/get_by-uuid/path-parameters.adoc[]

.HTTP Request
include::{snippets}/meeting/getList/success/http-request.adoc[]
include::{snippets}/meeting-controller-test/get_by-uuid/http-request.adoc[]

.HTTP Response
include::{snippets}/meeting/getList/success/http-response.adoc[]
include::{snippets}/meeting-controller-test/get_by-uuid/http-response.adoc[]

=== 모임 개별 조회 - 성공
include::{snippets}/meeting-controller-test/get_by-uuid/response-fields.adoc[]

include::{snippets}/meeting/get/success/path-parameters.adoc[]
=== 모임 확정 일정 수정

.HTTP Request
include::{snippets}/meeting/get/success/http-request.adoc[]
include::{snippets}/meeting-controller-test/update_confirmed-schedule/http-request.adoc[]

include::{snippets}/meeting-controller-test/update_confirmed-schedule/request-fields.adoc[]

.HTTP Response
include::{snippets}/meeting/get/success/http-response.adoc[]
include::{snippets}/meeting-controller-test/update_confirmed-schedule/http-response.adoc[]

=== 모임 개별 조회 - 실패

include::{snippets}/meeting/get/fail/path-parameters.adoc[]

.HTTP Request
include::{snippets}/meeting/get/fail/http-request.adoc[]

include::{snippets}/meeting/get/fail/http-response.adoc[]

=== 모임 수정 - 성공

include::{snippets}/meeting/update/success/path-parameters.adoc[]

.HTTP Request
include::{snippets}/meeting/update/success/http-request.adoc[]


.Request Fields
include::{snippets}/meeting/update/success/request-fields.adoc[]



.HTTP Response
include::{snippets}/meeting/update/success/http-response.adoc[]

=== 모임 수정 - 실패

.HTTP Request
include::{snippets}/meeting/update/fail/http-request.adoc[]

.HTTP Response
include::{snippets}/meeting/update/fail/http-response.adoc[]

=== 모임 삭제 - 성공

include::{snippets}/meeting/delete/success/path-parameters.adoc[]
.HTTP Request
include::{snippets}/meeting/delete/success/http-request.adoc[]

.HTTP Response
include::{snippets}/meeting/delete/success/http-response.adoc[]

=== 모임 삭제 - 실패

include::{snippets}/meeting/delete/fail/path-parameters.adoc[]
=== 모임 삭제

.HTTP Request
include::{snippets}/meeting/delete/fail/http-request.adoc[]
include::{snippets}/meeting-controller-test/delete_success/path-parameters.adoc[]
include::{snippets}/meeting-controller-test/delete_success/http-request.adoc[]

.HTTP Response
include::{snippets}/meeting/delete/fail/http-response.adoc[]
include::{snippets}/meeting-controller-test/delete_success/http-response.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dnd.jjakkak.domain.jwt.exception;

import com.dnd.jjakkak.global.exception.GeneralException;

public class AccessTokenExpiredException extends GeneralException {
private static final String MESSAGE = "엑세스 토큰이 만료됨.";

public AccessTokenExpiredException() {
super(MESSAGE);
}

@Override
public int getStatusCode() {
return 401;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dnd.jjakkak.domain.jwt.exception;

import com.dnd.jjakkak.global.exception.GeneralException;

public class MalformedTokenException extends GeneralException {
private static final String MESSAGE = "손상된 토큰.";

public MalformedTokenException() {
super(MESSAGE);
}

@Override
public int getStatusCode() {
return 401;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.dnd.jjakkak.domain.jwt.filter;

import com.dnd.jjakkak.domain.jwt.exception.AccessTokenExpiredException;
import com.dnd.jjakkak.domain.jwt.exception.MalformedTokenException;
import com.dnd.jjakkak.domain.jwt.provider.JwtProvider;
import com.dnd.jjakkak.domain.member.entity.Member;
import com.dnd.jjakkak.domain.member.entity.Role;
import com.dnd.jjakkak.domain.member.exception.MemberNotFoundException;
import com.dnd.jjakkak.domain.member.repository.MemberRepository;
import com.dnd.jjakkak.global.config.security.SecurityConfig;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* 검증을 실행하는 필터입니다.
*
* @author 류태웅
* @version 2024. 08. 03.
*/

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;
private final MemberRepository memberRepository;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String path = request.getRequestURI();
if(PatternMatchUtils.simpleMatch(SecurityConfig.WHITE_LIST, path)){
log.debug("path: {} -> passed token filter", path);
filterChain.doFilter(request, response);
}
String token = parseBearerToken(request);
log.debug("도착한 토큰: {}", token);
if (token == null) { // Bearer 인증 방식이 아니거나 빈 값일 경우 진행하지 말고 다음 필터로 바로 넘김
filterChain.doFilter(request, response);
return;
}
String kakaoId;
try {
kakaoId = jwtProvider.validate(token);
log.debug("검증된 카카오 ID: {}", kakaoId);
} catch (ExpiredJwtException e) {
log.error("엑세스 토큰이 만료됨", e);
throw new AccessTokenExpiredException();
} catch (MalformedJwtException e) {
log.error("손상된 토큰", e);
throw new MalformedTokenException();
}

if (kakaoId == null) {
filterChain.doFilter(request, response);
return;
}

Member member = memberRepository.findByKakaoId(Long.parseLong(kakaoId))
.orElseThrow(MemberNotFoundException::new);
Role role = member.getRole();

List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(role.toString()));

SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
AbstractAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(member, null, authorities);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

securityContext.setAuthentication(authenticationToken);
SecurityContextHolder.setContext(securityContext);

filterChain.doFilter(request, response);
}

private String parseBearerToken(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (StringUtils.hasText(authorization) && authorization.startsWith("Bearer ")) {
return authorization.substring(7);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.dnd.jjakkak.domain.jwt.handler;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
* 검증 실패 시 예외 처리 링크로 이동하는 핸들러입니다.
*
* @author 류태웅
* @version 2024. 08. 02.
*/

@Component
public class OAuth2FailureHandler extends SimpleUrlAuthenticationFailureHandler {

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
String errorMessage;
if(e instanceof UsernameNotFoundException){
errorMessage="존재하지 않는 아이디 입니다.";
}
else{
errorMessage="알 수 없는 이유로 로그인이 안되고 있습니다.";
}

errorMessage= URLEncoder.encode(errorMessage, StandardCharsets.UTF_8);//한글 인코딩 깨지는 문제 방지
response.sendRedirect("http://localhost:8080/auth/oauth-response/error="+errorMessage);
}
}
Loading

0 comments on commit d7478c0

Please sign in to comment.