Skip to content

Commit

Permalink
Merge pull request #185 from Kernel360/develop
Browse files Browse the repository at this point in the history
Develop to Main merge
  • Loading branch information
ShineCorine authored Nov 23, 2023
2 parents 425ffe8 + a57e4f0 commit 00b5148
Show file tree
Hide file tree
Showing 88 changed files with 945 additions and 44,263 deletions.
169 changes: 161 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,175 @@
# Orury!
![orury_mockup](https://github.com/Kernel360/E2E1-Orury/assets/44130863/41f0692c-2c24-4709-9f05-aa05827e66be)

당신만의 클라이밍 커뮤니티, 오루리
<div style="text-align: center;">
당신만의 클라이밍 커뮤니티, 오루리! <br>
내 클라이밍 라이프를 다른 클라이머들과 공유하고, 즐기세요!
</div>


## 멤버
|Backend| Backend |Backend|Backend|
|:---:|:-----------------------------------------------------------------------------------------------------------------------------:|:---:|:---:|
|<img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/eacb9aab-4a9b-4447-b516-9c5efe4484ce" width=100>| <img src="https://github.com/Kernel360/E2E1-Orury/assets/44130863/6fb7dacf-c5b6-4023-840f-96912da62910" width=100> |<img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/1ee6dd72-c060-4dab-996b-e9f9bc7048d2" width=100>|<img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/bef79d6c-5ec0-43c0-999c-906d42ad1e06" width=100>|
|[형준](https://github.com/kkkapuq)| [찬욱](https://github.com/mooncw) |[종민](https://github.com/ShineCorine)|[무룡](https://github.com/aqrms)|
| Backend | Backend | Backend | Backend |
|:-----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------:|
| <img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/eacb9aab-4a9b-4447-b516-9c5efe4484ce" width=300> | <img src="https://github.com/Kernel360/E2E1-Orury/assets/44130863/6fb7dacf-c5b6-4023-840f-96912da62910" width=300> | <img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/1ee6dd72-c060-4dab-996b-e9f9bc7048d2" width=300> | <img src="https://github.com/Kernel360-4cell/algorithm-study/assets/44130863/bef79d6c-5ec0-43c0-999c-906d42ad1e06" width=300> |
| [형준](https://github.com/kkkapuq) | [찬욱](https://github.com/mooncw) | [종민](https://github.com/ShineCorine) | [무룡](https://github.com/aqrms) |
| 팀원들이 본<br>**형준**| 팀원들이 본<br>**찬욱**| 팀원들이 본<br>**종민**| 팀원들이 본<br>**무룡**|
| 중심을 잡아줘요<br>리더쉽이 강해요<br>솔선수범한 리더 | 다재다능 행동대장<br>뭐든지 꼼꼼해요<br>팀의 해결사 | 부딪히고 보는 진격의 개발자<br>꾸준하게 성장해요<br>실력이 쑥쑥자라요 | 끝까지 가면 내가이겨<br>어려운 일도 파고들어요<br>책임감이 강해요 |

## 기술 스택
<img src="https://github.com/Kernel360/E2E1-Orury/assets/44130863/48959e1d-06d5-4b0a-be68-6d83ff143040" width=400, height=800>
<img src="https://github.com/Kernel360/E2E1-Orury/assets/44130863/48959e1d-06d5-4b0a-be68-6d83ff143040" width=500, height=1000>

## 서비스 흐름도
![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/ef0c31d3-623a-4ef8-b9a8-2a8fe0e5706b)
![서비스 흐름도](https://github.com/Kernel360/E2E1-Orury/assets/44130863/20cd677f-370a-4312-a271-73a25436069d)

## CI/CD
![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/23132200-f87c-4137-ad4b-6227a6174caa)
![image](https://github.com/Kernel360/E2E1-Orury/assets/44130863/d928aeb7-02e3-4909-96da-1bf31734ef4f)

## 시스템 아키텍처
![system_architecture](https://github.com/Kernel360/E2E1-Orury/assets/44130863/22def7c2-e141-4592-a03d-3858e362dcc1)

## ERD
![ERD](https://github.com/Kernel360/E2E1-Orury/assets/44130863/af21f3c1-4bd2-4703-a765-5a1a3534e3d7)

## 프로젝트 구조도
> 📦orury
┣ 📂batch
┃ ┣ 📂job
┃ ┃ ┗ 📜DeleteExpiredTokenJobConfig.java
┃ ┗ 📂scheduler
┃ ┃ ┗ 📜BatchScheduler.java
┣ 📂config
┃ ┣ 📂jwt
┃ ┃ ┣ 📜CustomAuthenticationFailureHandler.java
┃ ┃ ┣ 📜JwtAccessDeniedHandler.java
┃ ┃ ┣ 📜JwtAuthenticationEntryPoint.java
┃ ┃ ┣ 📜JwtFilter.java
┃ ┃ ┣ 📜JwtSecurityConfig.java
┃ ┃ ┗ 📜TokenProvider.java
┃ ┣ 📜CorsConfig.java
┃ ┣ 📜JasyptConfig.java
┃ ┣ 📜SecurityConfig.java
┃ ┗ 📜SwaggerConfig.java
┣ 📂domain
┃ ┣ 📂admin
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┣ 📜AdminBoardController.java
┃ ┃ ┃ ┣ 📜AdminCommentController.java
┃ ┃ ┃ ┣ 📜AdminPostController.java
┃ ┃ ┃ ┗ 📜AdminUserController.java
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┣ 📜AdminCommentService.java
┃ ┃ ┃ ┣ 📜AdminPostService.java
┃ ┃ ┃ ┗ 📜AdminUserService.java
┃ ┣ 📂board
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┗ 📜BoardController.java
┃ ┃ ┣ 📂db
┃ ┃ ┃ ┣ 📜BoardEntity.java
┃ ┃ ┃ ┗ 📜BoardRepository.java
┃ ┃ ┣ 📂model
┃ ┃ ┃ ┣ 📜BoardDto.java
┃ ┃ ┃ ┗ 📜BoardRequest.java
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┣ 📜BoardConverter.java
┃ ┃ ┃ ┗ 📜BoardService.java
┃ ┣ 📂comment
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┗ 📜CommentController.java
┃ ┃ ┣ 📂db
┃ ┃ ┃ ┣ 📜CommentEntity.java
┃ ┃ ┃ ┣ 📜CommentLikeEntity.java
┃ ┃ ┃ ┣ 📜CommentLikePK.java
┃ ┃ ┃ ┣ 📜CommentLikeRepository.java
┃ ┃ ┃ ┗ 📜CommentRepository.java
┃ ┃ ┣ 📂model
┃ ┃ ┃ ┣ 📜CommentDto.java
┃ ┃ ┃ ┣ 📜CommentLikeDto.java
┃ ┃ ┃ ┣ 📜CommentLikeRequest.java
┃ ┃ ┃ ┗ 📜CommentRequest.java
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┣ 📜CommentConverter.java
┃ ┃ ┃ ┗ 📜CommentService.java
┃ ┣ 📂config
┃ ┣ 📂notification
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┗ 📜NotifyController.java
┃ ┃ ┣ 📂db
┃ ┃ ┃ ┗ 📜EmitterRepository.java
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┗ 📜NotifyService.java
┃ ┣ 📂post
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┗ 📜PostController.java
┃ ┃ ┣ 📂db
┃ ┃ ┃ ┣ 📜PostEntity.java
┃ ┃ ┃ ┣ 📜PostLikeEntity.java
┃ ┃ ┃ ┣ 📜PostLikePK.java
┃ ┃ ┃ ┣ 📜PostLikeRepository.java
┃ ┃ ┃ ┗ 📜PostRepository.java
┃ ┃ ┣ 📂model
┃ ┃ ┃ ┣ 📜PostDto.java
┃ ┃ ┃ ┣ 📜PostLikeDto.java
┃ ┃ ┃ ┣ 📜PostLikeRequest.java
┃ ┃ ┃ ┗ 📜PostRequest.java
┃ ┃ ┣ 📂repository
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┣ 📜PostConverter.java
┃ ┃ ┃ ┗ 📜PostService.java
┃ ┗ 📂user
┃ ┃ ┣ 📂controller
┃ ┃ ┃ ┣ 📜AuthController.java
┃ ┃ ┃ ┗ 📜UserController.java
┃ ┃ ┣ 📂db
┃ ┃ ┃ ┣ 📜AuthorityEntity.java
┃ ┃ ┃ ┣ 📜AuthorityRepository.java
┃ ┃ ┃ ┣ 📜RefreshTokenEntity.java
┃ ┃ ┃ ┣ 📜RefreshTokenRepository.java
┃ ┃ ┃ ┣ 📜UserEntity.java
┃ ┃ ┃ ┗ 📜UserRepository.java
┃ ┃ ┣ 📂model
┃ ┃ ┃ ┣ 📜AuthorityDto.java
┃ ┃ ┃ ┣ 📜LoginDto.java
┃ ┃ ┃ ┣ 📜TokenDto.java
┃ ┃ ┃ ┣ 📜UserDto.java
┃ ┃ ┃ ┗ 📜UserResponseDto.java
┃ ┃ ┗ 📂service
┃ ┃ ┃ ┣ 📜CustomUserDetailsService.java
┃ ┃ ┃ ┗ 📜UserService.java
┣ 📂global
┃ ┣ 📂common
┃ ┃ ┣ 📜Api.java
┃ ┃ ┣ 📜ApiResponse.java
┃ ┃ ┣ 📜ApiStatus.java
┃ ┃ ┣ 📜BaseEntity.java
┃ ┃ ┣ 📜Listener.java
┃ ┃ ┣ 📜Pagination.java
┃ ┃ ┗ 📜SecurityUtil.java
┃ ┣ 📂config
┃ ┃ ┗ 📜JpaConfig.java
┃ ┣ 📂constants
┃ ┃ ┗ 📜Constant.java
┃ ┣ 📂controller
┃ ┣ 📂error
┃ ┃ ┣ 📂code
┃ ┃ ┃ ┣ 📜AuthorizationErrorCode.java
┃ ┃ ┃ ┣ 📜BoardErrorCode.java
┃ ┃ ┃ ┣ 📜CertificationErrorCode.java
┃ ┃ ┃ ┣ 📜CommentErrorCode.java
┃ ┃ ┃ ┣ 📜ErrorCode.java
┃ ┃ ┃ ┣ 📜PostErrorCode.java
┃ ┃ ┃ ┣ 📜ServerErrorCode.java
┃ ┃ ┃ ┗ 📜UserErrorCode.java
┃ ┃ ┣ 📂dto
┃ ┃ ┃ ┗ 📜ErrorResponse.java
┃ ┃ ┣ 📂exception
┃ ┃ ┃ ┗ 📜BusinessException.java
┃ ┃ ┗ 📜GlobalExceptionHandler.java
┃ ┗ 📂message
┃ ┃ ┣ 📂info
┃ ┃ ┃ ┗ 📜InfoMessages.java
┃ ┃ ┣ 📂success
┃ ┃ ┗ 📂validation
┗ 📜OruryApplication.java

## 사용법
### 1. apk를 다운받아서 사용하는 경우
Expand Down
1 change: 1 addition & 0 deletions backend/orury/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ build/
!**/src/test/**/build/
LOCAL_LOG_URL_IS_UNDEFINED
.DS_Store
AWS_LOG_URL_IS_UNDEFINED/

### STS ###
.apt_generated
Expand Down
3 changes: 3 additions & 0 deletions backend/orury/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ dependencies {
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.7.0'

implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package com.kernel360.orury.config;

import com.kernel360.orury.config.jwt.*;
import com.kernel360.orury.config.jwt.admin.AdminJwtAuthenticationEntryPoint;
import com.kernel360.orury.config.jwt.admin.AdminJwtFilter;
import com.kernel360.orury.domain.user.db.UserRepository;
import com.kernel360.orury.domain.user.service.CustomUserDetailsService;

import lombok.RequiredArgsConstructor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
Expand All @@ -35,20 +41,77 @@ public class SecurityConfig {
"/api/notify/**" // sse 테스트를 위해 임시로
);
private final TokenProvider tokenProvider;
private final UserRepository userRepository;
private final CorsFilter corsFilter;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final AdminJwtAuthenticationEntryPoint adminJwtAuthenticationEntryPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private CustomAuthenticationFailureHandler failureHandler;
private final CustomUserDetailsService customUserDetailsService;
@Value("${jwt.cookie-name}")
private String cookieName;
@Value("${jwt.refresh-cookie-name}")
private String cookieRefreshName;
@Value("${jwt.access-validity}")
private String accessCookieMaxAge;
@Value("${jwt.refresh-validity}")
private String refreshCookieMaxAge;

@Bean
public PasswordEncoder passwordEncoder() {
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public AuthenticationManager authenticationManager(
HttpSecurity http,
BCryptPasswordEncoder passwordEncoder
) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.build();
}

@Bean
@Order(1)
public SecurityFilterChain adminFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws
Exception {
http
// token을 사용하는 방식이기 때문에 csrf를 disable합니다.
.requestMatchers(requestMatchers -> requestMatchers
.antMatchers("/admin/**") // /api로 시작하는 요청을 처리
)
.csrf(csrf -> csrf.disable())

.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(exceptionHandling -> exceptionHandling
.accessDeniedHandler(jwtAccessDeniedHandler)
.authenticationEntryPoint(adminJwtAuthenticationEntryPoint)
)

.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
.mvcMatchers(SWAGGER.toArray(new String[0])).permitAll()
.antMatchers("/admin/login").permitAll()
.anyRequest().authenticated()
)

// 세션을 사용하지 않기 때문에 STATELESS로 설정
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
// JWT필터 적용
.addFilterBefore(new AdminJwtFilter(tokenProvider, cookieName, cookieRefreshName, accessCookieMaxAge,
refreshCookieMaxAge), UsernamePasswordAuthenticationFilter.class);
return http.build();
}

@Bean
@Order(2)
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http
.requestMatchers(requestMatchers -> requestMatchers
.antMatchers("/api/**") // /api로 시작하는 요청을 처리
)
.csrf(csrf -> csrf.disable())

.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kernel360.orury.global.common.ApiResponse;
import com.kernel360.orury.global.message.errors.ErrorMessages;
import com.kernel360.orury.global.error.code.CertificationErrorCode;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
Expand All @@ -20,7 +20,7 @@ public void onAuthenticationFailure(HttpServletRequest request, HttpServletRespo

// 여기에 원하는 JSON 응답을 작성합니다.
// 예시로는 ApiResponse를 사용했습니다.
ApiResponse apiResponse = ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, ErrorMessages.EXPIRED_JWT.getMessage());
ApiResponse apiResponse = ApiResponse.error(HttpStatus.UNAUTHORIZED, 401, CertificationErrorCode.EXPIRED_ACCESS_JWT.getMessage());
new ObjectMapper().writeValue(response.getWriter(), apiResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException
) {
resolver.resolveException(request, response, null, (Exception) request.getAttribute("exception"));
// JwtFilter에서 처리한 밣생한 예외를 받는 부분
if(request.getAttribute("exception") != null) {
resolver.resolveException(request, response, null, (Exception) request.getAttribute("exception"));
}

// jwt token에서 정의한 에러 외 filter에서 발생한 예외를 global handler로 보냄
else {
resolver.resolveException(request, response, null, authException);
}
// 유효한 자격증명을 제공하지 않고 접근하려 할때 401
// response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
Expand Down
Loading

0 comments on commit 00b5148

Please sign in to comment.