Skip to content

Commit

Permalink
Merge pull request #8 from DO-SOPT-SERVER/feature/7
Browse files Browse the repository at this point in the history
[6주차] 기본 과제 & 심화 과제
  • Loading branch information
SunwoongH authored Dec 11, 2023
2 parents 3406b0c + c53e90e commit 93bb2e4
Show file tree
Hide file tree
Showing 60 changed files with 843 additions and 191 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: ✔️ 체크아웃 합니다.
- name: ✔️ checkout
uses: actions/checkout@v3

- name: ✔️ JDK 17로 설정합니다.
- name: ✔️ set JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: ✔️ application.yml 파일을 생성합니다.
- name: ✔️ create application.yml
run: |
cd ./api/src/main
cd ./seminar-api/src/main
mkdir resources
cd ./resources
echo "$APPLICATION" > ./application.yml
env:
APPLICATION: ${{ secrets.APPLICATION }}

- name: ✔️ gradle build 를 위한 권한을 부여합니다.
- name: ✔️ set permission
run: chmod +x gradlew

- name: ✔️ gradle build 합니다.
run: ./gradlew api:build
- name: ✔️ build gradle
run: ./gradlew seminar-api:build
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ out/
.DS_Store

### Yml ###
api/src/main/resources/application.yml
seminar-api/src/main/resources/application.yml
16 changes: 0 additions & 16 deletions api/build.gradle

This file was deleted.

54 changes: 0 additions & 54 deletions api/src/main/java/org/sopt/api/member/api/MemberApiController.java

This file was deleted.

This file was deleted.

66 changes: 0 additions & 66 deletions api/src/main/java/org/sopt/api/member/service/MemberService.java

This file was deleted.

23 changes: 23 additions & 0 deletions seminar-api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
dependencies {
// spring boot web
implementation 'org.springframework.boot:spring-boot-starter-web'
// spring data jpa
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// spring security
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation project(path: ':seminar-infra')
// h2
runtimeOnly 'com.h2database:h2'
// jwt
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
// domain dependency
implementation project(path: ':seminar-domain')
// common dependency
implementation project(path: ':seminar-common')
}

jar {
enabled = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.api.auth;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class BCryptPasswordConfig {
private static final int STRENGTH = 10;

@Bean
public PasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder(STRENGTH);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.sopt.api.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.sopt.api.common.ApiResponse;
import org.sopt.api.common.Constants;
import org.sopt.common.error.ErrorStatus;
import org.sopt.common.error.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.io.PrintWriter;

public class ExceptionHandlerFilter extends OncePerRequestFilter {
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException {
try {
filterChain.doFilter(request, response);
} catch (UnauthorizedException e) {
handleUnauthorizedException(response, e);
} catch (Exception ee) {
handleException(response);
}
}

private void handleUnauthorizedException(HttpServletResponse response, Exception e) throws IOException {
UnauthorizedException ue = (UnauthorizedException) e;
ErrorStatus errorStatus = ue.getErrorStatus();
HttpStatus httpStatus = errorStatus.getHttpStatus();
setResponse(response, httpStatus, errorStatus);
}

private void handleException(HttpServletResponse response) throws IOException {
setResponse(response, HttpStatus.INTERNAL_SERVER_ERROR, ErrorStatus.INTERNAL_SERVER_ERROR);
}

private void setResponse(HttpServletResponse response, HttpStatus httpStatus, ErrorStatus errorStatus) throws IOException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Constants.CHARACTER_TYPE);
response.setStatus(httpStatus.value());
PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(ApiResponse.of(errorStatus)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.sopt.api.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.sopt.api.common.ApiResponse;
import org.sopt.api.common.Constants;
import org.sopt.common.error.ErrorStatus;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final ObjectMapper objectMapper = new ObjectMapper();

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
handleException(response);
}

private void handleException(HttpServletResponse response) throws IOException {
setResponse(response, HttpStatus.UNAUTHORIZED, ErrorStatus.UNAUTHORIZED);
}

private void setResponse(HttpServletResponse response, HttpStatus httpStatus, ErrorStatus errorStatus) throws IOException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Constants.CHARACTER_TYPE);
response.setStatus(httpStatus.value());
PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(ApiResponse.of(errorStatus)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.sopt.api.auth;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.sopt.api.auth.jwt.JwtProvider;
import org.sopt.api.auth.jwt.JwtValidator;
import org.sopt.api.common.Constants;
import org.sopt.common.error.ErrorStatus;
import org.sopt.common.error.UnauthorizedException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import static org.sopt.api.auth.UserAuthentication.createDefaultUserAuthentication;

@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtValidator jwtValidator;
private final JwtProvider jwtProvider;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
final String accessToken = getAccessToken(request);
jwtValidator.validateAccessToken(accessToken);
setAuthentication(request, jwtProvider.getSubject(accessToken));
filterChain.doFilter(request, response);
}

private String getAccessToken(HttpServletRequest request) {
String accessToken = request.getHeader(Constants.AUTHORIZATION);
if (StringUtils.hasText(accessToken) && accessToken.startsWith(Constants.BEARER)) {
return accessToken.substring(Constants.BEARER.length());
}
throw new UnauthorizedException(ErrorStatus.INVALID_ACCESS_TOKEN);
}

private void setAuthentication(HttpServletRequest request, Long memberId) {
UserAuthentication authentication = createDefaultUserAuthentication(memberId);
createWebAuthenticationDetailsAndSet(request, authentication);
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
}

private void createWebAuthenticationDetailsAndSet(HttpServletRequest request, UserAuthentication authentication) {
WebAuthenticationDetailsSource webAuthenticationDetailsSource = new WebAuthenticationDetailsSource();
WebAuthenticationDetails webAuthenticationDetails = webAuthenticationDetailsSource.buildDetails(request);
authentication.setDetails(webAuthenticationDetails);
}
}
11 changes: 11 additions & 0 deletions seminar-api/src/main/java/org/sopt/api/auth/MemberId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.api.auth;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface MemberId {
}
Loading

0 comments on commit 93bb2e4

Please sign in to comment.