Skip to content

Commit

Permalink
Merge pull request #70 from JNU-econovation/BE
Browse files Browse the repository at this point in the history
Slack Oauth 2.0 기능 개발
  • Loading branch information
capDoYeonLee authored Jul 18, 2024
2 parents a90dfad + f6210a7 commit c6fb40a
Show file tree
Hide file tree
Showing 77 changed files with 1,995 additions and 10 deletions.
28 changes: 26 additions & 2 deletions BE/error/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'org.springframework.boot' version '3.0.0'
id 'io.spring.dependency-management' version '1.1.4'
}

Expand All @@ -21,14 +21,38 @@ repositories {
mavenCentral()
}

ext {
set('springCloudVersion', "2022.0.0")
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}


dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation group: 'org.javassist', name: 'javassist', version: '3.15.0-GA'

// implementation 'org.springframework.cloud:spring-cloud-starter-config'
// implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

implementation 'org.hibernate:hibernate-validator:5.2.4.Final'

//implementation 'org.springframework.boot:spring-boot-starter-security'
}

tasks.named('test') {
Expand Down
62 changes: 62 additions & 0 deletions BE/error/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ services:
- ./resources/develop-environment/mysql-init.d:/docker-entrypoint-initdb.d
networks: #사용할 네트워크 지정
- error-network

redis:
container_name: redis
image: redis:latest
expose:
- "6379"
environment:
- REDIS_PASSWORD=root
networks:
- error-network

backend:
build:
context: .
Expand All @@ -29,7 +40,58 @@ services:
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
SPRING_PROFILES_ACTIVE: dev
SPRING_REDIS_HOST: error-redis
SPRING_REDIS_PORT: 6379
SPRING_REDIS_PASSWORD: root


networks: #사용할 네트워크 지정
- error-network
#
# cadvisor:
# image: gcr.io/cadvisor/cadvisor:v0.47.0
# container_name: cAdvisor
# privileged: true
# command:
# - '-port=8090'
# ports:
# - "8090:8090"
# volumes:
# - /:/rootfs:ro
# - /var/run:/var/run:ro
# - /var/run/docker.sock:/var/run/docker.sock:ro
# - /sys:/sys:ro
# - /var/lib/docker/:/var/lib/docker:ro
# - /dev/disk/:/dev/disk:ro
# networks:
# - error-network
#
# prometheus:
# image: prom/prometheus:v2.44.0
# container_name: prometheus
# ports:
# - "9090:9090"
# volumes:
# - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
# - ./prometheus/alert_rules.yml:/prometheus/alert_rules.yml
# networks:
# - error-network
#
# grafana:
# image: grafana/grafana:9.5.2
# container_name: grafana
# ports:
# - "3000:3000"
# volumes:
# - ./grafana/provisioning/datasources/:/etc/grafana/provisioning/datasources/
# - ./grafana/provisioning/dashboards/:/etc/grafana/provisioning/dashboards/
# - ./grafana/data/:/var/lib/grafana/dashboards/
# environment:
# - GF_AUTH_BASIC_ENABLED=false
# - GF_AUTH_ANONYMOUS_ENABLED=true
# - GF_AUTH_ANONYMOUS_ORG_ROLE=Editor
# networks:
# - error-network

networks:
error-network:
2 changes: 2 additions & 0 deletions BE/error/src/main/java/com/example/demo/ErrorApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
Expand All @@ -12,6 +13,7 @@
@EnableJpaRepositories
@SpringBootApplication
@EnableJpaAuditing
@EnableFeignClients(basePackages = "com.example.demo.auth.infra.oauth.slack.client")
public class ErrorApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.example.demo.auth.application.config;


import com.example.demo.auth.application.model.token.TokenResolver;
import com.example.demo.auth.application.support.CookieTokenExtractor;
import com.example.demo.auth.application.support.HeaderTokenExtractor;
import com.example.demo.auth.application.support.MemberArgumentResolver;
import com.example.demo.auth.presentation.interceptor.AuthInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@RequiredArgsConstructor
public class LoginConfig implements WebMvcConfigurer {
private final MemberArgumentResolver memberArgumentResolver;
private final TokenResolver tokenResolver;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(memberAuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/guest/**", "/api/auth/**", "/api/health-check","/api/programs/**");
registry
.addInterceptor(reissueAuthInterceptor())
.addPathPatterns("/auth/reissue")
.excludePathPatterns("/api/guest/**", "/api/auth/**", "/api/health-check");
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(memberArgumentResolver);
}

@Bean
public AuthInterceptor memberAuthInterceptor() {
return AuthInterceptor.builder()
.tokenExtractor(new HeaderTokenExtractor())
.tokenResolver(tokenResolver)
.build();
}

@Bean
public AuthInterceptor reissueAuthInterceptor() {
return AuthInterceptor.builder()
.tokenExtractor(new CookieTokenExtractor())
.tokenResolver(tokenResolver)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.demo.auth.application.dto;

import com.example.demo.common.support.dto.AbstractDto;
import com.example.demo.common.support.dto.AbstractResponseDto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder = true)
public class TokenResponse implements AbstractResponseDto {
private String accessToken;
private Long accessExpiredTime;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.demo.auth.application.event;

import lombok.Getter;

@Getter
public class DeletedMemberEvent {
private final Long memberId;
private final String token;

private DeletedMemberEvent(Long memberId, String token) {
this.memberId = memberId;
this.token = token;
}

/**
* 멤버 탈퇴 이벤트를 발행한다.
*
* @param memberId 회원 탈퇴를 원하는 멤버 id
* @param token 회원 탈퇴 시 사용한 토큰
* @return
*/
public static DeletedMemberEvent of(Long memberId, String token) {
return new DeletedMemberEvent(memberId, token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.demo.auth.application.exception;

import com.example.demo.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

public class AuthorizationException extends BusinessException {
public AuthorizationException(String code, HttpStatus httpStatus) {
super(code, httpStatus);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.demo.auth.application.exception;

import com.example.demo.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

/** 멤버의 이름 형식이 올바르지 않을 떄 발생하는 예외 */
public class InvalidNameFormatException extends BusinessException {
private static final String FAIL_CODE = "4006";
private final String name;

public InvalidNameFormatException(String name) {
super(FAIL_CODE, HttpStatus.BAD_REQUEST);
this.name = name;
}

@Override
public String getMessage() {
return String.format("%s 멤버의 이름이 형식과 일치하지 않습니다.", name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.demo.auth.application.exception;

import org.springframework.http.HttpStatus;

/** 토큰이 유효하지 않을 때 발생하는 예외 */
public class InvalidTokenException extends AuthorizationException {
private static final String FAIL_CODE = "4003";

public InvalidTokenException() {
super(FAIL_CODE, HttpStatus.UNAUTHORIZED);
}

@Override
public String getMessage() {
return "유효하지 않은 토큰입니다.";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.demo.auth.application.exception;

import com.example.demo.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

/** 토큰이 쿠키에 존재하지 않을 때 발생하는 예외 */
public class NotFoundCookieException extends BusinessException {
private static final String FAIL_CODE = "4004";

public NotFoundCookieException() {
super(FAIL_CODE, HttpStatus.UNAUTHORIZED);
}

@Override
public String getMessage() {
return "리프레시 토큰이 존재하지 않습니다.";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.demo.auth.application.exception;

import org.springframework.http.HttpStatus;

/** 토큰이 헤더에 존재하지 않을 때 발생하는 예외 */
public class NotFoundHeaderTokenException extends AuthorizationException {
private static final String FAIL_CODE = "4000";

public NotFoundHeaderTokenException() {
super(FAIL_CODE, HttpStatus.UNAUTHORIZED);
}

@Override
public String getMessage() {
return "엑세스 토큰이 존재하지 않습니다.";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.demo.auth.application.exception;

import com.example.demo.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

/** 존재하지 않는 oauth 서버일 때 발생하는 예외 */
public class NotFoundOauthServerException extends BusinessException {
private static final String FAIL_CODE = "5000";
private final String oauthServer;

public NotFoundOauthServerException(String oauthServer) {
super(FAIL_CODE, HttpStatus.NOT_FOUND);
this.oauthServer = oauthServer;
}

@Override
public String getMessage() {
return String.format("%s 는 존재하지 oauth 서버입니다.", oauthServer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.demo.auth.application.exception;


import org.springframework.http.HttpStatus;

public class TokenExpiredException extends AuthorizationException {

private static final String FAIL_CODE = "4001";

public TokenExpiredException() {
super(FAIL_CODE, HttpStatus.FORBIDDEN);
}

@Override
public String getMessage() {
return "액세스 토큰이 만료되었습니다.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.demo.auth.application.exception;

import com.example.demo.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

/** JWT 파싱 중 발생한 예외 */
public class TokenParsingException extends BusinessException {
private static final String FAIL_CODE = "4007";
private String message;

public TokenParsingException(Exception e) {
super(FAIL_CODE, HttpStatus.BAD_REQUEST);
message = e.getMessage();
}

@Override
public String getMessage() {
return String.format("JWT 파싱 중 오류 발생: {}", message);
}
}
Loading

0 comments on commit c6fb40a

Please sign in to comment.