From 32c8eb80d149c075305d34b783305a766d84f62d Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:49:49 +0900 Subject: [PATCH 01/66] =?UTF-8?q?feat:=20auth=20login=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/presentation/AuthController.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java new file mode 100644 index 00000000..855977ff --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java @@ -0,0 +1,63 @@ +package com.example.demo.auth.presentation; + +import com.example.demo.auth.application.dto.TokenResponse; +import com.example.demo.auth.application.model.TokenModel; +import com.example.demo.auth.application.model.converter.TokenResponseConverter; +import com.example.demo.auth.application.support.AuthConstants; +import com.example.demo.auth.application.usecase.LoginUsecase; +import com.example.demo.common.presentation.response.ApiResponse; +import com.example.demo.common.presentation.response.ApiResponseBody.SuccessBody; +import com.example.demo.common.presentation.response.ApiResponseGenerator; +import com.example.demo.common.presentation.response.MessageCode; +import com.example.demo.common.support.CookieManager; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/auth") +public class AuthController { + + private final LoginUsecase loginUsecase; + private final TokenResponseConverter tokenResponseConverter; + private final CookieManager cookieManager; + + + public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager) { + this.loginUsecase = loginUsecase; + this.tokenResponseConverter = tokenResponseConverter; + this.cookieManager = cookieManager; + } + + @Operation( + summary = "로그인을 한다.", + description = "PathVariable에 담긴 oauthServerType과 QuertParm인 redirect_url, code를 받아 액세스 토큰과 리프레시 토큰을 발급한다.") + @PostMapping("/login/{oauthServerType}") + ApiResponse> login( + @PathVariable String oauthServerType, + @RequestParam("code") String code, + @RequestParam("redirect_uri") String uri, + HttpServletResponse httpResponse) { + TokenModel tokenModel = loginUsecase.login(oauthServerType, code, uri); + TokenResponse response = generateTokenResponse(tokenModel, httpResponse); + + return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); + } + + + private TokenResponse generateTokenResponse( + TokenModel tokenModel, HttpServletResponse httpServletResponse) { + TokenResponse response = + tokenResponseConverter.from(tokenModel.getAccessToken(), tokenModel.getAccessExpiredTime()); + + ResponseCookie cookie = + cookieManager.setCookie(AuthConstants.TOKEN_KEY, tokenModel.getRefreshToken()); + httpServletResponse.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); + + return response; + } + +} From 043a95f6c4ac42614c6b49ff0735c4edb15d9b5e Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:50:13 +0900 Subject: [PATCH 02/66] =?UTF-8?q?feat:=20auth=20interceptor=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptor/AuthInterceptor.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java b/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java new file mode 100644 index 00000000..e221a30d --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java @@ -0,0 +1,57 @@ +package com.example.demo.auth.presentation.interceptor; + + +import com.example.demo.auth.application.model.token.TokenResolver; +import com.example.demo.auth.application.support.TokenExtractor; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.cors.CorsUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +public class AuthInterceptor implements HandlerInterceptor { + private final TokenExtractor tokenExtractor; + private final TokenResolver tokenResolver; + + public AuthInterceptor( + @Qualifier("header") TokenExtractor tokenExtractor, TokenResolver tokenResolver) { + this.tokenExtractor = tokenExtractor; + this.tokenResolver = tokenResolver; + } + + public static AuthInterceptorBuilder builder() { + return new AuthInterceptorBuilder(); + } + + @Override + public boolean preHandle( + HttpServletRequest request, HttpServletResponse response, Object handler) { + if (CorsUtils.isPreFlightRequest(request)) { + return true; + } + + String token = tokenExtractor.extract(request); + tokenResolver.getUserDataByAccessToken(token); + return true; + } + + public static class AuthInterceptorBuilder { + + private TokenExtractor tokenExtractor; + private TokenResolver tokenResolver; + + public AuthInterceptorBuilder tokenExtractor(TokenExtractor tokenExtractor) { + this.tokenExtractor = tokenExtractor; + return this; + } + + public AuthInterceptorBuilder tokenResolver(TokenResolver tokenResolver) { + this.tokenResolver = tokenResolver; + return this; + } + + public AuthInterceptor build() { + return new AuthInterceptor(tokenExtractor, tokenResolver); + } + } +} From cab6996b2f0f6b8db7bc1b74fd8cbb5283fafc0a Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:50:42 +0900 Subject: [PATCH 03/66] =?UTF-8?q?feat:=20member=20entity=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/persistence/MemberEntity.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/MemberEntity.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/MemberEntity.java b/BE/error/src/main/java/com/example/demo/auth/persistence/MemberEntity.java new file mode 100644 index 00000000..7b67fd04 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/MemberEntity.java @@ -0,0 +1,44 @@ +package com.example.demo.auth.persistence; + +import com.example.demo.auth.application.model.OauthServerType; +import com.example.demo.common.persistence.BaseEntity; +import jakarta.persistence.*; +import lombok.*; + +import lombok.experimental.SuperBuilder; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@ToString +@SuperBuilder(toBuilder = true) +@Entity +@Table( + name = MemberEntity.ENTITY_PREFIX, + indexes = { + @Index(name = "idx_member_name", columnList = "member_name"), + //@Index(name = "idx_member_active_status", columnList = "member_active_status") + }) +@EntityListeners(AuditingEntityListener.class) +public class MemberEntity extends BaseEntity { + + public static final String ENTITY_PREFIX = "member"; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = ENTITY_PREFIX + "_id", nullable = false) + private Long id; + + @Column(name = ENTITY_PREFIX + "_name", nullable = false) + private String name; + + @Column(name = ENTITY_PREFIX + "_oath_server_type", nullable = false) + @Enumerated(EnumType.STRING) + private OauthServerType oauthServerType; + +// @Column(name = ENTITY_PREFIX + "_active_status", nullable = false) +// @Enumerated(EnumType.STRING) +// @Builder.Default +// private ActiveStatus activeStatus = ActiveStatus.AM; +} From 6fde914bc12c51b0e494d193e9fbee62b04ec80d Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:51:04 +0900 Subject: [PATCH 04/66] =?UTF-8?q?feat:=20member=20repo=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/persistence/MemberRepository.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/MemberRepository.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/MemberRepository.java b/BE/error/src/main/java/com/example/demo/auth/persistence/MemberRepository.java new file mode 100644 index 00000000..9774aec0 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/MemberRepository.java @@ -0,0 +1,24 @@ +package com.example.demo.auth.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface MemberRepository extends JpaRepository { + +// @Query( +// "SELECT m FROM MemberEntity m inner join AttendEntity a on m.id = a.memberId where a.programId = :programId AND m.isDeleted=false ORDER BY m.name") +// List findMembersByProgramId(@Param("programId") Long programId); +// +// @Query( +// "SELECT m FROM MemberEntity m where m.activeStatus= :activeStatus AND m.isDeleted=false ORDER BY m.name") +// List findMembersByActiveStatus(@Param("activeStatus") ActiveStatus activeStatus); +// +// @Query("SELECT m FROM MemberEntity m WHERE m.isDeleted=false ORDER BY m.name") +// List findMembers(); +// +// @Query("SELECT m FROM MemberEntity m WHERE m.id IN :ids AND m.isDeleted=false ORDER BY m.name") +// List findMembersByIds(@Param("ids") List ids); +} From 351de943d1d741aea5b6cb83b0600c0a70a8876b Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:51:32 +0900 Subject: [PATCH 05/66] =?UTF-8?q?feat:=20auth=20member=20entity=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/persistence/OAuthMemberEntity.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberEntity.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberEntity.java b/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberEntity.java new file mode 100644 index 00000000..1cbd7daa --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberEntity.java @@ -0,0 +1,28 @@ +package com.example.demo.auth.persistence; + +import com.example.demo.common.persistence.BaseEntity; +import jakarta.persistence.*; +import lombok.*; +import lombok.experimental.SuperBuilder; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@ToString +@SuperBuilder(toBuilder = true) +@Entity +@Table(name = OAuthMemberEntity.ENTITY_PREFIX) +public class OAuthMemberEntity extends BaseEntity { + public static final String ENTITY_PREFIX = "oauth_member"; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = ENTITY_PREFIX + "_id", nullable = false) + private Long id; + + @Column(name = ENTITY_PREFIX + "_oauth_id", nullable = false) + private String oauthId; + + @Column(name = ENTITY_PREFIX + "_member_id", nullable = false) + private Long memberId; +} From d47d3f926e4cde56607bd67c8367e69708c1dcbd Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:51:50 +0900 Subject: [PATCH 06/66] =?UTF-8?q?feat:=20Oauth=20member=20repo=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/persistence/OAuthMemberRepository.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberRepository.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberRepository.java b/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberRepository.java new file mode 100644 index 00000000..270f870c --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/OAuthMemberRepository.java @@ -0,0 +1,15 @@ +package com.example.demo.auth.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Optional; + +public interface OAuthMemberRepository extends JpaRepository { + @Query("SELECT o FROM OAuthMemberEntity o WHERE o.oauthId=:oauthId") + Optional findByOauthId(@Param("oauthId") String oauthId); + + @Query("SELECT o FROM OAuthMemberEntity o WHERE o.memberId=:memberId") + Optional findByMemberId(@Param("memberId") Long memberId); +} From 1f220e0d1c54bbd21617780f187c4ec5446af31f Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:55:06 +0900 Subject: [PATCH 07/66] =?UTF-8?q?feat:=20slack=20=EC=A3=BC=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slack/client/SlackOauthMemberClient.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthMemberClient.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthMemberClient.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthMemberClient.java new file mode 100644 index 00000000..ee436cb4 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthMemberClient.java @@ -0,0 +1,93 @@ +package com.example.demo.auth.infra.oauth.slack.client; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.OauthServerType; +import com.example.demo.auth.application.model.client.OauthMemberClient; +import com.example.demo.auth.infra.oauth.slack.config.SlackOauthConfig; +import com.example.demo.auth.infra.oauth.slack.converter.OauthModelConverter; +import com.example.demo.auth.infra.oauth.slack.dto.SlackApiResponse; +import com.example.demo.auth.infra.oauth.slack.dto.SlackMember; +import com.example.demo.auth.infra.oauth.slack.dto.SlackToken; +import com.example.demo.auth.infra.oauth.slack.exception.SlackApiException; +import com.example.demo.auth.infra.oauth.slack.support.SlackFourQuery; +import com.example.demo.auth.infra.oauth.slack.support.SlackQuery; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + + + +@Component +@RequiredArgsConstructor +public class SlackOauthMemberClient implements OauthMemberClient { + private static final String TOKEN_METHOD_NAME = "getToken"; + private static final String MEMBER_INFO_METHOD_NAME = "getMemberInfo"; + private static final String BEARER = "Bearer"; + private static final Integer sum = 1; + + private final SlackOauthConfig oauthConfig; + private final SlackOauthApiClient slackApiClient; + private final OauthModelConverter oauthModelConverter; + + + @Override + public OauthServerType support() { + return OauthServerType.SLACK; + } + + @Override + public OauthMemberModel fetch(String code, String uri) { + + System.out.println("client ID : " + oauthConfig.getClientId()); + System.out.println("CODE :" + code); + System.out.println("Client Secret : " + oauthConfig.getClientSecret()); + System.out.println("URI : " + uri); + + SlackToken slackToken = + execute( + slackApiClient::fetchToken, + TOKEN_METHOD_NAME, + oauthConfig.getClientId(), + code, + oauthConfig.getClientSecret(), + uri); + + SlackMember slackMember = + execute( + slackApiClient::fetchMember, + MEMBER_INFO_METHOD_NAME, + requestToken(slackToken.getToken())); + + return oauthModelConverter.from( + slackToken.getUserId(), slackMember.getName(), OauthServerType.SLACK); + } + + private T execute( + final SlackFourQuery slackFunction, + final String methodName, + final K param1, + final U param2, + final R param3, + final S param4) { + T result = slackFunction.execute(param1, param2, param3, param4); + validateResponse(methodName, result); + return result; + } + + private T execute( + final SlackQuery slackFunction, final String methodName, final K request) { + T result = slackFunction.execute(request); + validateResponse(methodName, result); + return result; + } + + private String requestToken(String token) { + return String.format("%s %s", BEARER, token); + } + + private void validateResponse(String methodName, T response) { + if (!response.isOk()) { + System.out.println("validate Response: " + response.isOk()); + throw new SlackApiException(methodName, response); + } + } +} \ No newline at end of file From 6a31215c3b7d60320030337749c378c247d9a356 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:57:54 +0900 Subject: [PATCH 08/66] =?UTF-8?q?feat:=20SlackOauthApiClientImpl=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slack/client/SlackOauthApiClientImpl.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClientImpl.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClientImpl.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClientImpl.java new file mode 100644 index 00000000..71bcad8d --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClientImpl.java @@ -0,0 +1,25 @@ +package com.example.demo.auth.infra.oauth.slack.client; + +import com.example.demo.auth.infra.oauth.slack.dto.SlackMember; +import com.example.demo.auth.infra.oauth.slack.dto.SlackToken; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + + +@FeignClient(name = "SlackOpenFeign", url = "https://slack.com/api") +public interface SlackOauthApiClientImpl extends SlackOauthApiClient { + @GetMapping(path = "/oauth.v2.access") + SlackToken fetchToken( + @RequestParam("client_id") String clientId, + @RequestParam("code") String code, + @RequestParam("client_secret") String clientSecret, + @RequestParam("redirect_uri") String uri); + + + @GetMapping(path = "/users.profile.get") + SlackMember fetchMember(@RequestHeader("Authorization") String token); +} + From 8abe8fcc81f85cff069a700d04940156a7c2d5f4 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:58:25 +0900 Subject: [PATCH 09/66] =?UTF-8?q?feat:=20SlackOauthApiClient=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/oauth/slack/client/SlackOauthApiClient.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClient.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClient.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClient.java new file mode 100644 index 00000000..3d78b541 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/client/SlackOauthApiClient.java @@ -0,0 +1,11 @@ +package com.example.demo.auth.infra.oauth.slack.client; + +import com.example.demo.auth.infra.oauth.slack.dto.SlackMember; +import com.example.demo.auth.infra.oauth.slack.dto.SlackToken; + + +public interface SlackOauthApiClient { + SlackToken fetchToken(String client, String code, String clientSecret, String redirectUrl); + + SlackMember fetchMember(String token); +} From 633c5cfdb9e6cc6abc8618c5c0161e04f2cdce69 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:59:02 +0900 Subject: [PATCH 10/66] =?UTF-8?q?feat:=20slack=20oauth=20config=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/slack/config/SlackOauthConfig.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/config/SlackOauthConfig.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/config/SlackOauthConfig.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/config/SlackOauthConfig.java new file mode 100644 index 00000000..75ba527d --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/config/SlackOauthConfig.java @@ -0,0 +1,21 @@ +package com.example.demo.auth.infra.oauth.slack.config; + + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@PropertySource("classpath:/application.properties") +@Configuration +@Setter +@Getter +public class SlackOauthConfig { + + @Value("${spring.config.activate.on-profile.oauth.provider.slack.clientId}") + private String clientId; + + @Value("${spring.config.activate.on-profile.oauth.provider.slack.cliientSecret}") + private String clientSecret; +} From eecea62d16dede7d0843319cf0723f0189193fe7 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 19:59:40 +0900 Subject: [PATCH 11/66] =?UTF-8?q?feat:=20OauthModelConverter=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/slack/converter/OauthModelConverter.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/converter/OauthModelConverter.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/converter/OauthModelConverter.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/converter/OauthModelConverter.java new file mode 100644 index 00000000..7dc3dd44 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/converter/OauthModelConverter.java @@ -0,0 +1,13 @@ +package com.example.demo.auth.infra.oauth.slack.converter; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.OauthServerType; +import org.springframework.stereotype.Component; + +@Component +public class OauthModelConverter { + public OauthMemberModel from( + final String oauthId, final String name, final OauthServerType type) { + return OauthMemberModel.builder().oauthId(oauthId).name(name).oauthServerType(type).build(); + } +} From 002f720131edf8098d974dceb80fb68471356661 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:00:14 +0900 Subject: [PATCH 12/66] =?UTF-8?q?feat:=20SlackApiResponse=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/infra/oauth/slack/dto/SlackApiResponse.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackApiResponse.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackApiResponse.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackApiResponse.java new file mode 100644 index 00000000..f376239c --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackApiResponse.java @@ -0,0 +1,7 @@ +package com.example.demo.auth.infra.oauth.slack.dto; + +public interface SlackApiResponse { + boolean isOk(); + + String getError(); +} From 59a9cc501df750ffb7ef76956d958da20e1c48b4 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:00:53 +0900 Subject: [PATCH 13/66] =?UTF-8?q?feat:=20=EC=8A=AC=EB=9E=99=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/SlackChatPostMessageResponse.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackChatPostMessageResponse.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackChatPostMessageResponse.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackChatPostMessageResponse.java new file mode 100644 index 00000000..b17a6755 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackChatPostMessageResponse.java @@ -0,0 +1,60 @@ +package com.example.demo.auth.infra.oauth.slack.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@Builder +@NoArgsConstructor +public class SlackChatPostMessageResponse implements SlackApiResponse { + + private boolean ok; + + @JsonProperty("channel") + private String channel; + + @JsonProperty("ts") + private String timestamp; + + private Message message; + + private String error; + + @Override + public String getError() { + return error; + } + + public String getMessage() { + return message.getText(); + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + @Builder + public static class Message { + private String text; + private String userName; + private String botId; + private Attachment[] attachments; + private String type; + private String subType; + private String ts; + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Builder + public static class Attachment { + private String text; + private String id; + private String fallback; + } +} \ No newline at end of file From 2cbd464db6a50401ee59ae46e15c8a0b7b24feb5 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:01:16 +0900 Subject: [PATCH 14/66] =?UTF-8?q?feat:=20SlackErrorApiResponse=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/slack/dto/SlackErrorApiResponse.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackErrorApiResponse.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackErrorApiResponse.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackErrorApiResponse.java new file mode 100644 index 00000000..36d89ed5 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackErrorApiResponse.java @@ -0,0 +1,15 @@ +package com.example.demo.auth.infra.oauth.slack.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class SlackErrorApiResponse implements SlackApiResponse { + private boolean ok; + private String error; +} From cbc3adbdf494c8312f07854bbb4fcece2787ee3b Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:01:54 +0900 Subject: [PATCH 15/66] =?UTF-8?q?feat:=20SlackMember=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/oauth/slack/dto/SlackMember.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackMember.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackMember.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackMember.java new file mode 100644 index 00000000..96e7f562 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackMember.java @@ -0,0 +1,38 @@ +package com.example.demo.auth.infra.oauth.slack.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@Builder +@NoArgsConstructor +public class SlackMember implements SlackApiResponse { + private boolean ok; + + @JsonProperty("profile") + private UserProfile profile; + + private String error; + + @Override + public String getError() { + return error; + } + + @Getter + @AllArgsConstructor + @Builder + @NoArgsConstructor + public static class UserProfile { + @JsonProperty("display_name") + private String displayName; + } + + public String getName() { + return getProfile().getDisplayName(); + } +} From d5d66882640af20f63fb26c66c0efc2588cf8198 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:02:31 +0900 Subject: [PATCH 16/66] =?UTF-8?q?feat:=20SlackToken=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/oauth/slack/dto/SlackToken.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackToken.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackToken.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackToken.java new file mode 100644 index 00000000..fce6a1a2 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/dto/SlackToken.java @@ -0,0 +1,45 @@ +package com.example.demo.auth.infra.oauth.slack.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SlackToken implements SlackApiResponse { + @JsonProperty("ok") + private boolean ok; + + @JsonProperty("authed_user") + private AuthedUser authedUser; + + private String error; + + @Override + public String getError() { + return error; + } + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + @ToString + public static class AuthedUser { + @JsonProperty("id") + private String userId; + + @JsonProperty("access_token") + private String accessToken; + } + + public String getUserId() { + return getAuthedUser().getUserId(); + } + + public String getToken() { + return getAuthedUser().getAccessToken(); + } +} \ No newline at end of file From 1a89849ecb1d2aaaebfb02a2ec6b125fa5462eb9 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:03:05 +0900 Subject: [PATCH 17/66] =?UTF-8?q?feat:=20=EC=8A=AC=EB=9E=99=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slack/exception/SlackApiException.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/exception/SlackApiException.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/exception/SlackApiException.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/exception/SlackApiException.java new file mode 100644 index 00000000..631b1d7e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/exception/SlackApiException.java @@ -0,0 +1,25 @@ +package com.example.demo.auth.infra.oauth.slack.exception; + +import com.example.demo.auth.infra.oauth.slack.dto.SlackApiResponse; +import com.example.demo.common.exception.BusinessException; +import org.springframework.http.HttpStatus; + +/** slack API에서 실패 응답을 받을 시 발생하는 예외 */ +public class SlackApiException extends BusinessException { + + private static final String FAIL_CODE = "5000"; + private final String apiMethod; + private final SlackApiResponse slackApiResponse; + + public SlackApiException(final String apiMethod, final SlackApiResponse slackApiResponse) { + super(FAIL_CODE, HttpStatus.BAD_REQUEST); + this.apiMethod = apiMethod; + this.slackApiResponse = slackApiResponse; + } + + @Override + public String getMessage() { + return String.format( + "슬랙 API 호출 실패 : %s api 호출 , %s로 응답", apiMethod, slackApiResponse.getError()); + } +} From 5ddbdb37cba2afac7cf4fb6f68a092cf0c48df15 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:03:37 +0900 Subject: [PATCH 18/66] =?UTF-8?q?feat:=20SlackFourQuery=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/infra/oauth/slack/support/SlackFourQuery.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackFourQuery.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackFourQuery.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackFourQuery.java new file mode 100644 index 00000000..06f9f5ff --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackFourQuery.java @@ -0,0 +1,8 @@ +package com.example.demo.auth.infra.oauth.slack.support; + +import com.example.demo.auth.infra.oauth.slack.dto.SlackApiResponse; + +@FunctionalInterface +public interface SlackFourQuery { + T execute(K k, U u, V v, S s); +} \ No newline at end of file From 8f5f15484e4605244cad202d90f949603308ac84 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:04:00 +0900 Subject: [PATCH 19/66] =?UTF-8?q?feat:=20SlackQuery=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/infra/oauth/slack/support/SlackQuery.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackQuery.java diff --git a/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackQuery.java b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackQuery.java new file mode 100644 index 00000000..218d7360 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/infra/oauth/slack/support/SlackQuery.java @@ -0,0 +1,9 @@ +package com.example.demo.auth.infra.oauth.slack.support; + +import com.example.demo.auth.infra.oauth.slack.dto.SlackApiResponse; + +@FunctionalInterface +public interface SlackQuery { + T execute(K request); +} + From dd398844e60cada69841aef68e39879fa7d8499c Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:08:20 +0900 Subject: [PATCH 20/66] =?UTF-8?q?feat:=20LoginConfig=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/config/LoginConfig.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/config/LoginConfig.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/config/LoginConfig.java b/BE/error/src/main/java/com/example/demo/auth/application/config/LoginConfig.java new file mode 100644 index 00000000..3f336a50 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/config/LoginConfig.java @@ -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 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(); + } +} From e0c18d112441c66721c4be4304b25da42e4875ec Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:09:07 +0900 Subject: [PATCH 21/66] =?UTF-8?q?feat:=20TokenResponse=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/dto/TokenResponse.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/dto/TokenResponse.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/dto/TokenResponse.java b/BE/error/src/main/java/com/example/demo/auth/application/dto/TokenResponse.java new file mode 100644 index 00000000..32f927b3 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/dto/TokenResponse.java @@ -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; + +} From fdfeb3ff558ab4fc5ef1732b94eb65c0a0d047ad Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:10:18 +0900 Subject: [PATCH 22/66] =?UTF-8?q?feat:=20slack=20auth=20exception=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/AuthorizationException.java | 10 ++++++++++ .../exception/InvalidNameFormatException.java | 20 +++++++++++++++++++ .../exception/NotFoundCookieException.java | 19 ++++++++++++++++++ .../NotFoundHeaderTokenException.java | 18 +++++++++++++++++ .../NotFoundOauthServerException.java | 20 +++++++++++++++++++ .../exception/TokenExpiredException.java | 18 +++++++++++++++++ .../exception/TokenParsingException.java | 20 +++++++++++++++++++ 7 files changed, 125 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/AuthorizationException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidNameFormatException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundCookieException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundHeaderTokenException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundOauthServerException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/TokenExpiredException.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/TokenParsingException.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/AuthorizationException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/AuthorizationException.java new file mode 100644 index 00000000..cfb285cc --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/AuthorizationException.java @@ -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); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidNameFormatException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidNameFormatException.java new file mode 100644 index 00000000..3e1b6d88 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidNameFormatException.java @@ -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); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundCookieException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundCookieException.java new file mode 100644 index 00000000..7ae33dfe --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundCookieException.java @@ -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 "리프레시 토큰이 존재하지 않습니다."; + } +} + diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundHeaderTokenException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundHeaderTokenException.java new file mode 100644 index 00000000..4488e784 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundHeaderTokenException.java @@ -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 "엑세스 토큰이 존재하지 않습니다."; + } +} + diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundOauthServerException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundOauthServerException.java new file mode 100644 index 00000000..5eaaace3 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/NotFoundOauthServerException.java @@ -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); + } +} \ No newline at end of file diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenExpiredException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenExpiredException.java new file mode 100644 index 00000000..fc5099d8 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenExpiredException.java @@ -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 "액세스 토큰이 만료되었습니다."; + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenParsingException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenParsingException.java new file mode 100644 index 00000000..a8a74fed --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/TokenParsingException.java @@ -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); + } +} From e02d8949273ef2982d646ab3644c1e04392efc47 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:11:18 +0900 Subject: [PATCH 23/66] =?UTF-8?q?feat:=20MemberModel=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/model/MemberModel.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/MemberModel.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/MemberModel.java b/BE/error/src/main/java/com/example/demo/auth/application/model/MemberModel.java new file mode 100644 index 00000000..cee384b0 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/MemberModel.java @@ -0,0 +1,43 @@ +package com.example.demo.auth.application.model; + +import com.example.demo.common.application.model.MemberIdModel; +import com.example.demo.common.support.AbstractModel; +import lombok.*; + +@Getter +@ToString +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class MemberModel implements AbstractModel, MemberIdModel { + private Long id; + private String name; + //private ActiveStatus activeStatus; + private OauthServerType oauthServerType; + +// public MemberModel updateActiveStatus(String status) { +// ActiveStatus requestStatus = ActiveStatus.find(status); +// canEdit(requestStatus); +// this.activeStatus = requestStatus; +// return this; +// } +// +// public boolean validateSame(Long memberId) { +// return id.equals(memberId); +// } +// +// public String getActiveStatus() { +// return activeStatus.getStatus(); +// } +// +// private void canEdit(ActiveStatus requestStatus) { +// if (requestStatus.isAll()) { +// throw new DeniedUpdateActiveException(requestStatus.getStatus()); +// } +// } + + @Override + public Long getMemberId() { + return id; + } +} \ No newline at end of file From c8463ced1f26e10ef7dab5f340c2d97258279e9b Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:11:44 +0900 Subject: [PATCH 24/66] =?UTF-8?q?feat:=20OauthMemberModel=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/model/OauthMemberModel.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/OauthMemberModel.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/OauthMemberModel.java b/BE/error/src/main/java/com/example/demo/auth/application/model/OauthMemberModel.java new file mode 100644 index 00000000..f8347159 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/OauthMemberModel.java @@ -0,0 +1,24 @@ +package com.example.demo.auth.application.model; + +import com.example.demo.auth.application.exception.InvalidNameFormatException; +import com.example.demo.auth.application.support.ValidatorNameFormat; +import com.example.demo.common.support.AbstractModel; +import lombok.*; + + +@Getter +@ToString +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class OauthMemberModel implements AbstractModel { + private String oauthId; + private String name; + private OauthServerType oauthServerType; + + public void validateNameFormat() { + if (!ValidatorNameFormat.isSatisfy(name)) { + throw new InvalidNameFormatException(name); + } + } +} \ No newline at end of file From b4f5cee6c13b3e0c26f2542566b0a83e990de64f Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:12:03 +0900 Subject: [PATCH 25/66] =?UTF-8?q?feat:=20OauthServerType=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/model/OauthServerType.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/OauthServerType.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/OauthServerType.java b/BE/error/src/main/java/com/example/demo/auth/application/model/OauthServerType.java new file mode 100644 index 00000000..03155e58 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/OauthServerType.java @@ -0,0 +1,25 @@ +package com.example.demo.auth.application.model; + +import com.example.demo.auth.application.exception.NotFoundOauthServerException; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +public enum OauthServerType { + SLACK("slack"); + + private final String oauthServer; + + OauthServerType(String oauthServer) { + this.oauthServer = oauthServer; + } + + public static OauthServerType find(String type) { + return Arrays.stream(values()) + .filter(oauthServerType -> oauthServerType.getOauthServer().equals(type)) + .findAny() + .orElseThrow(() -> new NotFoundOauthServerException(type)); + } +} + From 2b84d478e65001bf1a05377ac30601366325e303 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:12:25 +0900 Subject: [PATCH 26/66] =?UTF-8?q?feat:=20TokenModel=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/model/TokenModel.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/TokenModel.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/TokenModel.java b/BE/error/src/main/java/com/example/demo/auth/application/model/TokenModel.java new file mode 100644 index 00000000..639b3957 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/TokenModel.java @@ -0,0 +1,17 @@ +package com.example.demo.auth.application.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class TokenModel { + private String accessToken; + private Long accessExpiredTime; + private String refreshToken; + private Long refreshExpiredTime; +} \ No newline at end of file From 281c8c18bd988d73efdae6d053439a9b6c8441a8 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:14:26 +0900 Subject: [PATCH 27/66] =?UTF-8?q?feat:=20OauthMemberClient=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/model/client/OauthMemberClient.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClient.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClient.java b/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClient.java new file mode 100644 index 00000000..db971dd5 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClient.java @@ -0,0 +1,10 @@ +package com.example.demo.auth.application.model.client; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.OauthServerType; + +public interface OauthMemberClient { + OauthServerType support(); + + OauthMemberModel fetch(String code, String uri); +} From fbfd307d033476f313fbf716d8344160813ccccc Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:14:52 +0900 Subject: [PATCH 28/66] =?UTF-8?q?-feat:=20OauthMemberClientComposite=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/OauthMemberClientComposite.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClientComposite.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClientComposite.java b/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClientComposite.java new file mode 100644 index 00000000..42320e0e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/client/OauthMemberClientComposite.java @@ -0,0 +1,31 @@ +package com.example.demo.auth.application.model.client; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.OauthServerType; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Component +public class OauthMemberClientComposite { + + private final Map clients; + + public OauthMemberClientComposite(Set providers) { + this.clients = + providers.stream() + .collect(Collectors.toMap(OauthMemberClient::support, Function.identity())); + } + + public OauthMemberModel fetch(String oauthServerType, String authCode, String uri) { + return getClient(oauthServerType).fetch(authCode, uri); + } + + private OauthMemberClient getClient(String type) { + OauthServerType oauthServerType = OauthServerType.find(type); + return clients.get(oauthServerType); + } +} From 07574cfebcf32c535c01cfd3f587ae36f1f2db7d Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:15:36 +0900 Subject: [PATCH 29/66] =?UTF-8?q?feat:=20slack=20api=20converter=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../converter/MemberEntityConverter.java | 34 +++++++++++++++++++ .../converter/OauthMemberEntityConverter.java | 24 +++++++++++++ .../model/converter/TokenModelConverter.java | 19 +++++++++++ .../converter/TokenResponseConverter.java | 14 ++++++++ 4 files changed, 91 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/converter/MemberEntityConverter.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/converter/OauthMemberEntityConverter.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenModelConverter.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenResponseConverter.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/converter/MemberEntityConverter.java b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/MemberEntityConverter.java new file mode 100644 index 00000000..592495e9 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/MemberEntityConverter.java @@ -0,0 +1,34 @@ +package com.example.demo.auth.application.model.converter; + +import com.example.demo.auth.application.model.MemberModel; +import com.example.demo.auth.application.model.OauthServerType; +import com.example.demo.auth.persistence.MemberEntity; +import com.example.demo.common.support.converter.AbstractEntityConverter; +import org.springframework.stereotype.Component; + +@Component +public class MemberEntityConverter implements AbstractEntityConverter { + + @Override + public MemberModel from(MemberEntity source) { + return MemberModel.builder() + .id(source.getId()) + .name(source.getName()) + .oauthServerType(source.getOauthServerType()) + .build(); + } + + @Override + public MemberEntity toEntity(MemberModel source) { + return MemberEntity.builder() + .id(source.getId()) + .name(source.getName()) + //.activeStatus(ActiveStatus.find(source.getActiveStatus())) + .oauthServerType(source.getOauthServerType()) + .build(); + } + + public MemberEntity toEntity(String name, OauthServerType oauthServerType) { + return MemberEntity.builder().name(name).oauthServerType(oauthServerType).build(); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/converter/OauthMemberEntityConverter.java b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/OauthMemberEntityConverter.java new file mode 100644 index 00000000..02af1271 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/OauthMemberEntityConverter.java @@ -0,0 +1,24 @@ +package com.example.demo.auth.application.model.converter; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.persistence.OAuthMemberEntity; +import com.example.demo.common.support.converter.AbstractEntityConverter; +import org.springframework.stereotype.Component; + +@Component +public class OauthMemberEntityConverter + implements AbstractEntityConverter { + @Override + public OauthMemberModel from(final OAuthMemberEntity entity) { + return OauthMemberModel.builder().oauthId(entity.getOauthId()).build(); + } + + @Override + public OAuthMemberEntity toEntity(final OauthMemberModel model) { + return OAuthMemberEntity.builder().oauthId(model.getOauthId()).build(); + } + + public OAuthMemberEntity toEntity(final String oauthId, Long memberId) { + return OAuthMemberEntity.builder().oauthId(oauthId).memberId(memberId).build(); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenModelConverter.java b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenModelConverter.java new file mode 100644 index 00000000..e4f79a31 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenModelConverter.java @@ -0,0 +1,19 @@ +package com.example.demo.auth.application.model.converter; + +import com.example.demo.auth.application.model.TokenModel; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class TokenModelConverter { + public TokenModel from( + String accessToken, Long accessExpiredTime, String refreshToken, Long refreshExpiredTime) { + return TokenModel.builder() + .accessToken(accessToken) + .accessExpiredTime(accessExpiredTime) + .refreshToken(refreshToken) + .refreshExpiredTime(refreshExpiredTime) + .build(); + } +} \ No newline at end of file diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenResponseConverter.java b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenResponseConverter.java new file mode 100644 index 00000000..024abdf1 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/converter/TokenResponseConverter.java @@ -0,0 +1,14 @@ +package com.example.demo.auth.application.model.converter; + +import com.example.demo.auth.application.dto.TokenResponse; +import org.springframework.stereotype.Component; + +@Component +public class TokenResponseConverter { + public TokenResponse from(String accessToken, Long accessExpiredTime) { + return TokenResponse.builder() + .accessToken(accessToken) + .accessExpiredTime(accessExpiredTime) + .build(); + } +} From 9d6bdeb04d9e9ac023ac80514ddf62a4c284d6bc Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:15:58 +0900 Subject: [PATCH 30/66] =?UTF-8?q?feat:=20auth=20token=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/token/TokenProvider.java | 59 +++++++++++++ .../model/token/TokenResolver.java | 82 +++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java new file mode 100644 index 00000000..af5632ea --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java @@ -0,0 +1,59 @@ +package com.example.demo.auth.application.model.token; + +import io.jsonwebtoken.Header; +import io.jsonwebtoken.Jwts; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import io.jsonwebtoken.security.Keys; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Component +@Slf4j +public class TokenProvider { + + private static final String MEMBER_ID_CLAIM_KEY = "memberId"; + private final SecretKey accessSecretKey; + private final SecretKey refreshSecretKey; + private final long accessValidTime; + private final long refreshValidTime; + + public TokenProvider( + @Value("${security.jwt.access.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String accessSecretKey, + @Value("${security.jwt.refresh.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String refreshSecretKey, + @Value("${security.jwt.access.validTime:3600}") long accessValidTime, + @Value("${security.jwt.refresh.validTime:3600}") long refreshValidTime) { + this.accessSecretKey = Keys.hmacShaKeyFor(accessSecretKey.getBytes(StandardCharsets.UTF_8)); + this.refreshSecretKey = Keys.hmacShaKeyFor(refreshSecretKey.getBytes(StandardCharsets.UTF_8)); + this.accessValidTime = accessValidTime; + this.refreshValidTime = refreshValidTime; + } + + public String createAccessToken(final Long memberId) { + final Date now = new Date(); + + return Jwts.builder() + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) + .claim(MEMBER_ID_CLAIM_KEY, memberId) + .setIssuedAt(now) + .setExpiration(new Date(now.getTime() + accessValidTime)) + .signWith(accessSecretKey) + .compact(); + } + + public String createRefreshToken(final Long memberId) { + final Date now = new Date(); + + return Jwts.builder() + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) + .claim(MEMBER_ID_CLAIM_KEY, memberId) + .setIssuedAt(now) + .setExpiration(new Date(now.getTime() + refreshValidTime)) + .signWith(refreshSecretKey) + .compact(); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java new file mode 100644 index 00000000..fd350ef8 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java @@ -0,0 +1,82 @@ +package com.example.demo.auth.application.model.token; + +import com.example.demo.auth.application.exception.TokenExpiredException; +import com.example.demo.auth.application.exception.TokenParsingException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.SignatureException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import javax.crypto.SecretKey; +import io.jsonwebtoken.security.Keys; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Component +@Slf4j +public class TokenResolver { + + private static final String MEMBER_ID_CLAIM_KEY = "memberId"; + private final SecretKey accessSecretKey; + private final SecretKey refreshSecretKey; + + public TokenResolver( + @Value("${security.jwt.access.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String accessSecretKey, + @Value("${security.jwt.refresh.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String refreshSecretKey) { + this.accessSecretKey = generateSecretKey(accessSecretKey); + this.refreshSecretKey = generateSecretKey(refreshSecretKey); + } + + public Long getExpiredDateByAccessToken(final String token) { + return getExpirationTime(getAccessClaims(token)); + } + + public Long getExpiredDateByRefreshToken(final String token) { + return getExpirationTime(getRefreshClaims(token)); + } + + public Long getUserDataByAccessToken(final String token) { + return getClaimValue(getAccessClaims(token), MEMBER_ID_CLAIM_KEY); + } + + public Long getUserDataByRefreshToken(final String token) { + return getClaimValue(getRefreshClaims(token), MEMBER_ID_CLAIM_KEY); + } + + private SecretKey generateSecretKey(String key) { + return Keys.hmacShaKeyFor(key.getBytes(StandardCharsets.UTF_8)); + } + + private Claims getAccessClaims(final String token) { + return parseClaims(token, accessSecretKey); + } + + private Claims getRefreshClaims(final String token) { + return parseClaims(token, refreshSecretKey); + } + + private Claims parseClaims(final String token, final SecretKey secretKey) { + try { + return Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody(); + } catch (ExpiredJwtException e) { + throw new TokenExpiredException(); + } catch (SignatureException e) { + throw new TokenParsingException(e); + } catch (Exception e) { + log.error("JWT 파싱 중 오류 발생: {}", e.getMessage(), e); + throw new TokenParsingException(e); + } + } + + private Long getExpirationTime(Claims claims) { + Date expiration = claims.getExpiration(); + return expiration.getTime(); + } + + private Long getClaimValue(Claims claims, String claimKey) { + return claims.get(claimKey, Long.class); + } +} From f2fe11fe97441622e7182859e1ea1f9ef4666dc0 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:16:56 +0900 Subject: [PATCH 31/66] =?UTF-8?q?feat:=20login=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/AuthFacadeService.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/service/AuthFacadeService.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/service/AuthFacadeService.java b/BE/error/src/main/java/com/example/demo/auth/application/service/AuthFacadeService.java new file mode 100644 index 00000000..719ff065 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/service/AuthFacadeService.java @@ -0,0 +1,24 @@ +package com.example.demo.auth.application.service; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.TokenModel; +import com.example.demo.auth.application.support.AuthenticationTokenGenerator; +import com.example.demo.auth.application.usecase.LoginUsecase; +import com.example.demo.auth.persistence.OAuthMemberEntity; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AuthFacadeService implements LoginUsecase { + private final OauthClientService oauthClientService; + private final AuthService authService; + private final AuthenticationTokenGenerator authenticationTokenGenerator; + + @Override + public TokenModel login(String oauthServerType, String authCode, String uri) { + OauthMemberModel model = oauthClientService.getOauthMember(oauthServerType, authCode, uri); + OAuthMemberEntity entity = authService.authenticate(model); + return authenticationTokenGenerator.execute(entity.getMemberId()); + } +} From 0fb5cb9163517c499b717da2fcc666b6e73406ea Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:17:23 +0900 Subject: [PATCH 32/66] =?UTF-8?q?feat:=20auth=20service=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/service/AuthService.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/service/AuthService.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/service/AuthService.java b/BE/error/src/main/java/com/example/demo/auth/application/service/AuthService.java new file mode 100644 index 00000000..0c2acc07 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/service/AuthService.java @@ -0,0 +1,40 @@ +package com.example.demo.auth.application.service; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.converter.MemberEntityConverter; +import com.example.demo.auth.application.model.converter.OauthMemberEntityConverter; +import com.example.demo.auth.persistence.MemberEntity; +import com.example.demo.auth.persistence.MemberRepository; +import com.example.demo.auth.persistence.OAuthMemberEntity; +import com.example.demo.auth.persistence.OAuthMemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AuthService { + private final MemberRepository memberRepository; + private final OAuthMemberRepository oAuthMemberRepository; + private final MemberEntityConverter memberEntityConverter; + private final OauthMemberEntityConverter oauthMemberEntityConverter; + + @Transactional + public OAuthMemberEntity authenticate(final OauthMemberModel model) { + return oAuthMemberRepository + .findByOauthId(model.getOauthId()) + .orElseGet(() -> signUpMember(model)); + } + + private OAuthMemberEntity signUpMember(final OauthMemberModel model) { + MemberEntity entity = memberEntityConverter.toEntity(model.getName(), model.getOauthServerType()); + MemberEntity savedMember = memberRepository.save(entity); + return saveOauthInfoEntity(model.getOauthId(), savedMember.getId()); + } + + private OAuthMemberEntity saveOauthInfoEntity(final String oauthId, final Long memberId) { + OAuthMemberEntity entity = oauthMemberEntityConverter.toEntity(oauthId, memberId); + return oAuthMemberRepository.save(entity); + } +} From 2dc9cdd391fb0170217e6791e8c73e81853a468c Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:17:56 +0900 Subject: [PATCH 33/66] =?UTF-8?q?feat:=20auth=20member=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/OauthClientService.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/service/OauthClientService.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/service/OauthClientService.java b/BE/error/src/main/java/com/example/demo/auth/application/service/OauthClientService.java new file mode 100644 index 00000000..feaa370e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/service/OauthClientService.java @@ -0,0 +1,19 @@ +package com.example.demo.auth.application.service; + +import com.example.demo.auth.application.model.OauthMemberModel; +import com.example.demo.auth.application.model.client.OauthMemberClientComposite; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class OauthClientService { + private final OauthMemberClientComposite oauthMemberClientComposite; + + public OauthMemberModel getOauthMember(String oauthServerType, String authCode, String uri) { + OauthMemberModel model = oauthMemberClientComposite.fetch(oauthServerType, authCode, uri); + model.validateNameFormat(); + + return model; + } +} From d9a33dbe77c5001787e6cb53816ed18ceaeba5c3 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:19:07 +0900 Subject: [PATCH 34/66] =?UTF-8?q?feat:=20auth=20support=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/support/AuthConstants.java | 5 ++ .../support/AuthCookieManager.java | 50 +++++++++++++++++++ .../support/AuthenticationTokenGenerator.java | 27 ++++++++++ .../support/CookieTokenExtractor.java | 44 ++++++++++++++++ .../support/HeaderTokenExtractor.java | 33 ++++++++++++ .../demo/auth/application/support/Member.java | 11 ++++ .../support/MemberArgumentResolver.java | 41 +++++++++++++++ .../application/support/TokenExtractor.java | 8 +++ .../support/ValidatorNameFormat.java | 12 +++++ 9 files changed, 231 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/AuthConstants.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/AuthenticationTokenGenerator.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/CookieTokenExtractor.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/HeaderTokenExtractor.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/Member.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/MemberArgumentResolver.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/TokenExtractor.java create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/support/ValidatorNameFormat.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/AuthConstants.java b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthConstants.java new file mode 100644 index 00000000..7232ee84 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthConstants.java @@ -0,0 +1,5 @@ +package com.example.demo.auth.application.support; + +public class AuthConstants { + public static final String TOKEN_KEY = "error_token"; +} \ No newline at end of file diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java new file mode 100644 index 00000000..0eddfb33 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java @@ -0,0 +1,50 @@ +package com.example.demo.auth.application.support; + +import com.example.demo.common.support.CookieManager; +import com.example.demo.common.utils.TimeUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseCookie; +import org.springframework.stereotype.Component; + +@Component +public class AuthCookieManager implements CookieManager { + + private static final Boolean HTTP_ONLY = true; + private static final Boolean SECURE = true; + private static final String SAMESITE = "None"; + private static final Long EXPIRATION = 0L; + + @Value("${token.cookie.domain:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") + private String domain; + + @Value("${token.cookie.path:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") + private String path; + + @Value("${security.jwt.refresh.validTime:3600}") + private Long validTime; + + @Override + public ResponseCookie setCookie(String key, String value) { + return ResponseCookie.from(key, value) + .path(path) + .domain(domain) + .httpOnly(HTTP_ONLY) + .secure(SECURE) + .sameSite(SAMESITE) + .maxAge(TimeUtil.convertSecondsFromMillis(validTime)) + .build(); + } + + @Override + public ResponseCookie deleteCookie(String key) { + return ResponseCookie.from(key, "") + .path(path) + .domain(domain) + .httpOnly(HTTP_ONLY) + .secure(SECURE) + .sameSite(SAMESITE) + .maxAge(TimeUtil.convertSecondsFromMillis(EXPIRATION)) + .build(); + } +} + diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/AuthenticationTokenGenerator.java b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthenticationTokenGenerator.java new file mode 100644 index 00000000..ad79cc38 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthenticationTokenGenerator.java @@ -0,0 +1,27 @@ +package com.example.demo.auth.application.support; + +import com.example.demo.auth.application.model.TokenModel; +import com.example.demo.auth.application.model.converter.TokenModelConverter; +import com.example.demo.auth.application.model.token.TokenProvider; +import com.example.demo.auth.application.model.token.TokenResolver; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class AuthenticationTokenGenerator { + private final TokenProvider tokenProvider; + private final TokenModelConverter tokenModelConverter; + private final TokenResolver tokenResolver; + + public TokenModel execute(final Long memberId) { + String accessToken = tokenProvider.createAccessToken(memberId); + String refreshToken = tokenProvider.createRefreshToken(memberId); + + return tokenModelConverter.from( + accessToken, + tokenResolver.getExpiredDateByAccessToken(accessToken), + refreshToken, + tokenResolver.getExpiredDateByRefreshToken(refreshToken)); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/CookieTokenExtractor.java b/BE/error/src/main/java/com/example/demo/auth/application/support/CookieTokenExtractor.java new file mode 100644 index 00000000..e65bad3e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/CookieTokenExtractor.java @@ -0,0 +1,44 @@ +package com.example.demo.auth.application.support; + + +import com.example.demo.auth.application.exception.NotFoundCookieException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Component("cookie") +public class CookieTokenExtractor implements TokenExtractor { + + @Override + public String extract(HttpServletRequest request) { + Cookie[] cookies = getCookies(request); + + for (Cookie cookie : cookies) { + if (Objects.equals(AuthConstants.TOKEN_KEY, cookie.getName())) { + return getValue(cookie.getValue()); + } + } + + throw new NotFoundCookieException(); + } + + private Cookie[] getCookies(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + + if (cookies == null) { + throw new NotFoundCookieException(); + } + + return cookies; + } + + private String getValue(String value) { + if (value != null) { + return value; + } + throw new NotFoundCookieException(); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/HeaderTokenExtractor.java b/BE/error/src/main/java/com/example/demo/auth/application/support/HeaderTokenExtractor.java new file mode 100644 index 00000000..9a73bac1 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/HeaderTokenExtractor.java @@ -0,0 +1,33 @@ +package com.example.demo.auth.application.support; + + +import com.example.demo.auth.application.exception.NotFoundHeaderTokenException; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; + +@Component(value = "header") +public class HeaderTokenExtractor implements TokenExtractor { + private static final String BEARER_TOKEN_PREFIX = "Bearer "; + + @Override + public String extract(HttpServletRequest request) { + String header = request.getHeader(HttpHeaders.AUTHORIZATION); + if (header == null) { + throw new NotFoundHeaderTokenException(); + } + return extractToken(header); + } + + private String extractToken(String header) { + validateHeader(header); + return header.substring(BEARER_TOKEN_PREFIX.length()).trim(); + } + + private void validateHeader(String header) { + if (!header.toLowerCase().startsWith(BEARER_TOKEN_PREFIX.toLowerCase())) { + throw new NotFoundHeaderTokenException(); + } + } +} + diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/Member.java b/BE/error/src/main/java/com/example/demo/auth/application/support/Member.java new file mode 100644 index 00000000..c0ca554d --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/Member.java @@ -0,0 +1,11 @@ +package com.example.demo.auth.application.support; + +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 Member {} + diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/MemberArgumentResolver.java b/BE/error/src/main/java/com/example/demo/auth/application/support/MemberArgumentResolver.java new file mode 100644 index 00000000..86f4096b --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/MemberArgumentResolver.java @@ -0,0 +1,41 @@ +package com.example.demo.auth.application.support; + +import com.example.demo.auth.application.model.token.TokenResolver; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +@Slf4j +public class MemberArgumentResolver implements HandlerMethodArgumentResolver { + private final TokenExtractor tokenExtractor; + private final TokenResolver tokenResolver; + + public MemberArgumentResolver( + @Qualifier(value = "header") TokenExtractor tokenExtractor, TokenResolver tokenResolver) { + this.tokenExtractor = tokenExtractor; + this.tokenResolver = tokenResolver; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(Member.class); + } + + @Override + public Object resolveArgument( + MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + String token = tokenExtractor.extract(request); + return tokenResolver.getUserDataByAccessToken(token); + } +} diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/TokenExtractor.java b/BE/error/src/main/java/com/example/demo/auth/application/support/TokenExtractor.java new file mode 100644 index 00000000..6ea5e6c5 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/TokenExtractor.java @@ -0,0 +1,8 @@ +package com.example.demo.auth.application.support; + +import jakarta.servlet.http.HttpServletRequest; + +public interface TokenExtractor { + + String extract(HttpServletRequest request); +} \ No newline at end of file diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/ValidatorNameFormat.java b/BE/error/src/main/java/com/example/demo/auth/application/support/ValidatorNameFormat.java new file mode 100644 index 00000000..f64452b6 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/ValidatorNameFormat.java @@ -0,0 +1,12 @@ +package com.example.demo.auth.application.support; + +import java.util.regex.Pattern; + +public class ValidatorNameFormat { + private static final String REGULAR_EXPRESSION = "^\\d{2}기.*"; + private static final Pattern FORMAT = Pattern.compile(REGULAR_EXPRESSION); + + public static boolean isSatisfy(String source) { + return FORMAT.matcher(source).matches(); + } +} From da2bd22e2f8a27d8c01f60eeb82d9478dc22c7e0 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Fri, 14 Jun 2024 20:19:36 +0900 Subject: [PATCH 35/66] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20use?= =?UTF-8?q?case=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/usecase/LoginUsecase.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/usecase/LoginUsecase.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/usecase/LoginUsecase.java b/BE/error/src/main/java/com/example/demo/auth/application/usecase/LoginUsecase.java new file mode 100644 index 00000000..f06ae572 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/usecase/LoginUsecase.java @@ -0,0 +1,7 @@ +package com.example.demo.auth.application.usecase; + +import com.example.demo.auth.application.model.TokenModel; + +public interface LoginUsecase { + TokenModel login(String oauthServerType, String authCode, String uri); +} \ No newline at end of file From f2e2bcdfbf5e32de3dde351326f4f7a2fc42bfb0 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Tue, 18 Jun 2024 10:20:40 +0900 Subject: [PATCH 36/66] =?UTF-8?q?feat:=20auth=20controller=20reissue=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/presentation/AuthController.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java index 855977ff..533cdb36 100644 --- a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java @@ -4,14 +4,19 @@ import com.example.demo.auth.application.model.TokenModel; import com.example.demo.auth.application.model.converter.TokenResponseConverter; import com.example.demo.auth.application.support.AuthConstants; +import com.example.demo.auth.application.support.HeaderTokenExtractor; +import com.example.demo.auth.application.support.TokenExtractor; import com.example.demo.auth.application.usecase.LoginUsecase; +import com.example.demo.auth.application.usecase.ReissueUsecase; import com.example.demo.common.presentation.response.ApiResponse; import com.example.demo.common.presentation.response.ApiResponseBody.SuccessBody; import com.example.demo.common.presentation.response.ApiResponseGenerator; import com.example.demo.common.presentation.response.MessageCode; import com.example.demo.common.support.CookieManager; import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; @@ -19,18 +24,22 @@ @RestController @RequestMapping("/api/auth") +@RequiredArgsConstructor public class AuthController { private final LoginUsecase loginUsecase; + private final ReissueUsecase reissueUsecase; private final TokenResponseConverter tokenResponseConverter; private final CookieManager cookieManager; + private final TokenExtractor tokenExtractor; - public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager) { - this.loginUsecase = loginUsecase; - this.tokenResponseConverter = tokenResponseConverter; - this.cookieManager = cookieManager; - } +// public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager, TokenExtractor tokenExtractor) { +// this.loginUsecase = loginUsecase; +// this.tokenResponseConverter = tokenResponseConverter; +// this.cookieManager = cookieManager; +// this.tokenExtractor = tokenExtractor; +// } @Operation( summary = "로그인을 한다.", @@ -47,6 +56,16 @@ ApiResponse> login( return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); } + @Operation(summary = "토큰을 재발급한다.", description = "쿠키에 담긴 사용자 토큰을 이용하여 리프레시 토큰을 반환한다.") + @PostMapping("/reissue") + ApiResponse> reissue(HttpServletRequest request, HttpServletResponse httpResonse) { + String token = tokenExtractor.extract(request); + TokenModel tokenModel = reissueUsecase.excute(token); + TokenResponse response = generateTokenResponse(tokenModel, httpResonse); + + return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); + } + private TokenResponse generateTokenResponse( TokenModel tokenModel, HttpServletResponse httpServletResponse) { From 5e8e793903c2a4b65958113928d1c4959f04f52c Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Sat, 13 Jul 2024 16:16:24 +0900 Subject: [PATCH 37/66] test commit --- .../demo/auth/presentation/AuthController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java index 533cdb36..91563267 100644 --- a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java @@ -24,7 +24,7 @@ @RestController @RequestMapping("/api/auth") -@RequiredArgsConstructor +//@RequiredArgsConstructor public class AuthController { private final LoginUsecase loginUsecase; @@ -34,12 +34,12 @@ public class AuthController { private final TokenExtractor tokenExtractor; -// public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager, TokenExtractor tokenExtractor) { -// this.loginUsecase = loginUsecase; -// this.tokenResponseConverter = tokenResponseConverter; -// this.cookieManager = cookieManager; -// this.tokenExtractor = tokenExtractor; -// } + public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager, TokenExtractor tokenExtractor) { + this.loginUsecase = loginUsecase; + this.tokenResponseConverter = tokenResponseConverter; + this.cookieManager = cookieManager; + this.tokenExtractor = tokenExtractor; + } @Operation( summary = "로그인을 한다.", @@ -60,7 +60,7 @@ ApiResponse> login( @PostMapping("/reissue") ApiResponse> reissue(HttpServletRequest request, HttpServletResponse httpResonse) { String token = tokenExtractor.extract(request); - TokenModel tokenModel = reissueUsecase.excute(token); + TokenModel tokenModel = reissueUsecase.execute(token); TokenResponse response = generateTokenResponse(tokenModel, httpResonse); return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); From de12c0c239710e2805fe3ae6f98f21bf117532e5 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:43:28 +0900 Subject: [PATCH 38/66] =?UTF-8?q?feat:=20logout=20usecase=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/auth/application/usecase/LogOutUsecase.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/usecase/LogOutUsecase.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/usecase/LogOutUsecase.java b/BE/error/src/main/java/com/example/demo/auth/application/usecase/LogOutUsecase.java new file mode 100644 index 00000000..8b37387b --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/usecase/LogOutUsecase.java @@ -0,0 +1,5 @@ +package com.example.demo.auth.application.usecase; + +public interface LogOutUsecase { + void logOut(String token, final long memberId); +} From 6f925fb36f70dfede4545795c081a511b2395205 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:44:41 +0900 Subject: [PATCH 39/66] =?UTF-8?q?feat:=20reissue=20usecase=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/usecase/ReissueUsecase.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/usecase/ReissueUsecase.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/usecase/ReissueUsecase.java b/BE/error/src/main/java/com/example/demo/auth/application/usecase/ReissueUsecase.java new file mode 100644 index 00000000..4249ccb2 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/usecase/ReissueUsecase.java @@ -0,0 +1,8 @@ +package com.example.demo.auth.application.usecase; + + +import com.example.demo.auth.application.model.TokenModel; + +public interface ReissueUsecase { + TokenModel execute(final String token); +} From 7c42734043a591df7dc88808b69f90b23391ddac Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:46:01 +0900 Subject: [PATCH 40/66] =?UTF-8?q?feat:=20withdraw=20usecase=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/usecase/WithDrawUsecase.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/usecase/WithDrawUsecase.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/usecase/WithDrawUsecase.java b/BE/error/src/main/java/com/example/demo/auth/application/usecase/WithDrawUsecase.java new file mode 100644 index 00000000..80f439d5 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/usecase/WithDrawUsecase.java @@ -0,0 +1,5 @@ +package com.example.demo.auth.application.usecase; + +public interface WithDrawUsecase { + void withDraw(String token, Long memberId); +} From 18f986011dc4ac1be17d919cc4ec1daa5f7468e8 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:48:04 +0900 Subject: [PATCH 41/66] =?UTF-8?q?fix:=20cookie=20domain=20and=20path=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/support/AuthCookieManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java index 0eddfb33..0e91b067 100644 --- a/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java +++ b/BE/error/src/main/java/com/example/demo/auth/application/support/AuthCookieManager.java @@ -14,10 +14,10 @@ public class AuthCookieManager implements CookieManager { private static final String SAMESITE = "None"; private static final Long EXPIRATION = 0L; - @Value("${token.cookie.domain:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") + @Value("${token.cookie.domain:http://localhost}") private String domain; - @Value("${token.cookie.path:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") + @Value("${token.cookie.path:/}") private String path; @Value("${security.jwt.refresh.validTime:3600}") From 4a6a8bdc91faebf86cfcb91b2f2d88107ae9e055 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:49:28 +0900 Subject: [PATCH 42/66] =?UTF-8?q?feat:=20reissue=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/ReissueService.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/service/ReissueService.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/service/ReissueService.java b/BE/error/src/main/java/com/example/demo/auth/application/service/ReissueService.java new file mode 100644 index 00000000..c0373e32 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/service/ReissueService.java @@ -0,0 +1,50 @@ +package com.example.demo.auth.application.service; + + +import com.example.demo.auth.application.exception.InvalidTokenException; +import com.example.demo.auth.application.model.TokenModel; +import com.example.demo.auth.application.model.token.TokenResolver; +import com.example.demo.auth.application.support.AuthenticationTokenGenerator; +import com.example.demo.auth.application.usecase.ReissueUsecase; +import com.example.demo.auth.persistence.AuthenticationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReissueService implements ReissueUsecase { + + private final TokenResolver tokenResolver; + private final AuthenticationTokenGenerator authenticationTokenGenerator; + private final AuthenticationRepository authenticationRepository; + + @Transactional + @Override + public TokenModel execute(final String token) { + + Long memberId = tokenResolver.getUserDataByRefreshToken(token); + + validateToken(token); + saveUsedToken(token, memberId); + + return authenticationTokenGenerator.execute(memberId); + } + + private void validateToken(final String token) { + boolean isExistToken = authenticationRepository.isExistToken(token); + + if (isExistToken) { + throw new InvalidTokenException(); + } + } + + private void saveUsedToken(final String token, final Long memberId) { + authenticationRepository.save(token, memberId, getExpiredToken(token)); + } + + private Long getExpiredToken(final String token) { + return tokenResolver.getExpiredDateByRefreshToken(token); + } +} From e206ac89233e4749d992c6d88f98dbf7d5b8e2eb Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:49:53 +0900 Subject: [PATCH 43/66] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20and=20=ED=9A=8C=EC=9B=90=ED=83=88=ED=87=B4=20servic?= =?UTF-8?q?e=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/DeactivateMemberService.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/service/DeactivateMemberService.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/service/DeactivateMemberService.java b/BE/error/src/main/java/com/example/demo/auth/application/service/DeactivateMemberService.java new file mode 100644 index 00000000..3b97bb32 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/service/DeactivateMemberService.java @@ -0,0 +1,59 @@ +package com.example.demo.auth.application.service; + +import com.example.demo.auth.application.event.DeletedMemberEvent; +import com.example.demo.auth.application.model.token.TokenResolver; +import com.example.demo.auth.application.usecase.LogOutUsecase; +import com.example.demo.auth.application.usecase.WithDrawUsecase; +import com.example.demo.auth.persistence.AuthenticationRepository; +import com.example.demo.auth.persistence.MemberRepository; +import com.example.demo.auth.persistence.OAuthMemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class DeactivateMemberService implements LogOutUsecase, WithDrawUsecase { + + private final TokenResolver tokenResolver; + private final AuthenticationRepository authenticationRepository; + private final MemberRepository memberRepository; + private final ApplicationEventPublisher eventPublisher; + private final OAuthMemberRepository oAuthMemberRepository; + + @Override + public void logOut(String token, long memberId) { + saveUsedToken(token, memberId); + } + + private void saveUsedToken(final String token, final Long memberId) { + authenticationRepository.save(token, memberId, getExpiredToken(token)); + } + + private Long getExpiredToken(final String token) { + return tokenResolver.getExpiredDateByRefreshToken(token); + } + + + @Override + @Transactional + public void withDraw(String token, Long memberId) { + if (isNotMember(memberId)) { + return; + } + deleteMemberData(memberId); + eventPublisher.publishEvent(DeletedMemberEvent.of(memberId, token)); + } + + private boolean isNotMember(Long memberId) { + return memberRepository.findById(memberId).isEmpty(); + } + + private void deleteMemberData(Long memberId) { + memberRepository.deleteById(memberId); + oAuthMemberRepository.findByMemberId(memberId).ifPresent(oAuthMemberRepository::delete); + } + +} From ad7f2680c1ba83541c541bc80625d6d46ecdcf94 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:52:35 +0900 Subject: [PATCH 44/66] =?UTF-8?q?fix:=20=ED=86=A0=ED=81=B0=20resolver=20?= =?UTF-8?q?=EC=8B=9C=ED=81=AC=EB=A6=BF=20=ED=82=A4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/model/token/TokenResolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java index fd350ef8..0ed4a024 100644 --- a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenResolver.java @@ -24,8 +24,8 @@ public class TokenResolver { private final SecretKey refreshSecretKey; public TokenResolver( - @Value("${security.jwt.access.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String accessSecretKey, - @Value("${security.jwt.refresh.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String refreshSecretKey) { + @Value("${security.jwt.access.secretKey:erroroverflowsecretekeyerroroverflowsecretekey}") String accessSecretKey, + @Value("${security.jwt.refresh.secretKey:erroroverflowsecretekeyerroroverflowsecretekey}") String refreshSecretKey) { this.accessSecretKey = generateSecretKey(accessSecretKey); this.refreshSecretKey = generateSecretKey(refreshSecretKey); } From 2e347910acefbfab0d79871c4e985ce8cc18d155 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:53:13 +0900 Subject: [PATCH 45/66] =?UTF-8?q?fix:=20=ED=86=A0=ED=81=B0=20resolver=20?= =?UTF-8?q?=EC=8B=9C=ED=81=AC=EB=A6=BF=20=ED=82=A4=20=EB=B0=8F=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EB=A7=8C=EB=A3=8C=20=ED=83=80=EC=9E=84=20=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/application/model/token/TokenProvider.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java index af5632ea..70da411e 100644 --- a/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java +++ b/BE/error/src/main/java/com/example/demo/auth/application/model/token/TokenProvider.java @@ -23,10 +23,10 @@ public class TokenProvider { private final long refreshValidTime; public TokenProvider( - @Value("${security.jwt.access.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String accessSecretKey, - @Value("${security.jwt.refresh.secretKey:TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST}") String refreshSecretKey, - @Value("${security.jwt.access.validTime:3600}") long accessValidTime, - @Value("${security.jwt.refresh.validTime:3600}") long refreshValidTime) { + @Value("${security.jwt.access.secretKey}") String accessSecretKey, + @Value("${security.jwt.refresh.secretKey}") String refreshSecretKey, + @Value("${security.jwt.access.validTime:3600000}") long accessValidTime, + @Value("${security.jwt.refresh.validTime:26280000}") long refreshValidTime) { this.accessSecretKey = Keys.hmacShaKeyFor(accessSecretKey.getBytes(StandardCharsets.UTF_8)); this.refreshSecretKey = Keys.hmacShaKeyFor(refreshSecretKey.getBytes(StandardCharsets.UTF_8)); this.accessValidTime = accessValidTime; From 79429ddcd6b0c184a5f86715a39de9b97d03380c Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:54:22 +0900 Subject: [PATCH 46/66] =?UTF-8?q?feat:=20=ED=86=A0=ED=81=B0=20=EC=9C=A0?= =?UTF-8?q?=EC=9A=94=ED=95=98=EC=A7=80=20=EC=95=88=EC=9D=84=20=EB=95=8C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/InvalidTokenException.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidTokenException.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidTokenException.java b/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidTokenException.java new file mode 100644 index 00000000..0e47201d --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/exception/InvalidTokenException.java @@ -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 "유효하지 않은 토큰입니다."; + } +} + From 9a179dee2ac123ae1d954864c2617f65dd2a3d2f Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:55:02 +0900 Subject: [PATCH 47/66] =?UTF-8?q?feat:=20delete=20member=20event=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/event/DeletedMemberEvent.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/application/event/DeletedMemberEvent.java diff --git a/BE/error/src/main/java/com/example/demo/auth/application/event/DeletedMemberEvent.java b/BE/error/src/main/java/com/example/demo/auth/application/event/DeletedMemberEvent.java new file mode 100644 index 00000000..ea39847e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/application/event/DeletedMemberEvent.java @@ -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); + } +} \ No newline at end of file From e78e35f87c480086f2013a1f8df38893bb3745a8 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:56:14 +0900 Subject: [PATCH 48/66] =?UTF-8?q?feat:=20AuthenticationEntity=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/AuthenticationEntity.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationEntity.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationEntity.java b/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationEntity.java new file mode 100644 index 00000000..77d92b75 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationEntity.java @@ -0,0 +1,20 @@ +package com.example.demo.auth.persistence; + +import lombok.*; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; +import org.springframework.data.redis.core.TimeToLive; + +@RedisHash("MemberAuthentication") +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class AuthenticationEntity { + @Id + private String token; + private Long memberId; + @TimeToLive + private Long expiration; +} \ No newline at end of file From 4df085d063ea3400c7e5cd48e95e2b91732ad203 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:56:46 +0900 Subject: [PATCH 49/66] =?UTF-8?q?feat:=20AuthenticationRepository=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/AuthenticationRepository.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationRepository.java diff --git a/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationRepository.java b/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationRepository.java new file mode 100644 index 00000000..52f91bff --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/auth/persistence/AuthenticationRepository.java @@ -0,0 +1,24 @@ +package com.example.demo.auth.persistence; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + + +import java.util.concurrent.TimeUnit; + +@Repository +@RequiredArgsConstructor +public class AuthenticationRepository { + + private final RedisTemplate redisTemplate; + + public void save(String token, Long memberId, Long expiration) { + redisTemplate.opsForValue().set(token, memberId, expiration, TimeUnit.MILLISECONDS); + } + + public Boolean isExistToken(String key) { + return redisTemplate.hasKey(key); + } +} + From 91379529cb349bd19576edc01f1673ff9213527a Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:57:34 +0900 Subject: [PATCH 50/66] =?UTF-8?q?feat:=20auth=20controller=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/presentation/AuthController.java | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java index 91563267..8fe30bdc 100644 --- a/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/AuthController.java @@ -4,10 +4,12 @@ import com.example.demo.auth.application.model.TokenModel; import com.example.demo.auth.application.model.converter.TokenResponseConverter; import com.example.demo.auth.application.support.AuthConstants; -import com.example.demo.auth.application.support.HeaderTokenExtractor; +import com.example.demo.auth.application.support.Member; import com.example.demo.auth.application.support.TokenExtractor; +import com.example.demo.auth.application.usecase.LogOutUsecase; import com.example.demo.auth.application.usecase.LoginUsecase; import com.example.demo.auth.application.usecase.ReissueUsecase; +import com.example.demo.auth.application.usecase.WithDrawUsecase; import com.example.demo.common.presentation.response.ApiResponse; import com.example.demo.common.presentation.response.ApiResponseBody.SuccessBody; import com.example.demo.common.presentation.response.ApiResponseGenerator; @@ -16,7 +18,7 @@ import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; @@ -24,21 +26,24 @@ @RestController @RequestMapping("/api/auth") -//@RequiredArgsConstructor public class AuthController { private final LoginUsecase loginUsecase; private final ReissueUsecase reissueUsecase; + private final LogOutUsecase logOutUsecase; + private final WithDrawUsecase withDrawUsecase; private final TokenResponseConverter tokenResponseConverter; private final CookieManager cookieManager; private final TokenExtractor tokenExtractor; - - public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager, TokenExtractor tokenExtractor) { + public AuthController(LoginUsecase loginUsecase, TokenResponseConverter tokenResponseConverter, CookieManager cookieManager, @Qualifier("cookie") TokenExtractor tokenExtractor, ReissueUsecase reissueUsecase, LogOutUsecase logOutUsecase, WithDrawUsecase withDrawUsecase) { this.loginUsecase = loginUsecase; this.tokenResponseConverter = tokenResponseConverter; this.cookieManager = cookieManager; this.tokenExtractor = tokenExtractor; + this.reissueUsecase = reissueUsecase; + this.logOutUsecase = logOutUsecase; + this.withDrawUsecase = withDrawUsecase; } @Operation( @@ -66,6 +71,30 @@ ApiResponse> reissue(HttpServletRequest request, Http return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); } + // 여기 부터 기능 구현 안됨 + @Operation(summary = "로그아웃한다.", description = "쿠키에 담긴 리프레시 토큰을 이용하여 로그아웃한다.") + @PostMapping("/logout") + ApiResponse> logout( + HttpServletRequest request, HttpServletResponse httpResponse, @Member Long memberId) { + String token = tokenExtractor.extract(request); + logOutUsecase.logOut(token, memberId); + deleteTokenResponse(httpResponse); + + return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.DELETE); + } + + @Operation(summary = "회원탈퇴", description = "쿠키에 담긴 리프레시 토큰을 이용하여 회원을 탈퇴한다.") + @PostMapping("/withdraw") + ApiResponse> withDraw( + HttpServletRequest request, HttpServletResponse httpResponse, @Member Long memberId) { + String token = tokenExtractor.extract(request); + withDrawUsecase.withDraw(token, memberId); + deleteTokenResponse(httpResponse); + + return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.DELETE); + } + // 여기 까지 기능 구현 안됨 + private TokenResponse generateTokenResponse( TokenModel tokenModel, HttpServletResponse httpServletResponse) { @@ -79,4 +108,9 @@ private TokenResponse generateTokenResponse( return response; } + private void deleteTokenResponse(HttpServletResponse httpServletResponse) { + ResponseCookie cookie = cookieManager.deleteCookie(AuthConstants.TOKEN_KEY); + httpServletResponse.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); + } + } From a10280b8e5328d55d2884c6060175eff9516fcd9 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 20:58:02 +0900 Subject: [PATCH 51/66] =?UTF-8?q?feat:=20auth=20interceptor=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/auth/presentation/interceptor/AuthInterceptor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java b/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java index e221a30d..55a6024d 100644 --- a/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java +++ b/BE/error/src/main/java/com/example/demo/auth/presentation/interceptor/AuthInterceptor.java @@ -31,6 +31,7 @@ public boolean preHandle( } String token = tokenExtractor.extract(request); + System.out.println("token :" + token); tokenResolver.getUserDataByAccessToken(token); return true; } From 119fcf595ec35bf2328fe88ec12427083cdaf8a3 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:00:25 +0900 Subject: [PATCH 52/66] =?UTF-8?q?feat:=20MemberIdModel=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/common/application/model/MemberIdModel.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/common/application/model/MemberIdModel.java diff --git a/BE/error/src/main/java/com/example/demo/common/application/model/MemberIdModel.java b/BE/error/src/main/java/com/example/demo/common/application/model/MemberIdModel.java new file mode 100644 index 00000000..3c1e6f83 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/common/application/model/MemberIdModel.java @@ -0,0 +1,5 @@ +package com.example.demo.common.application.model; + +public interface MemberIdModel { + Long getMemberId(); +} From 5cae194d60319d33ad2500e527388cca3737307c Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:00:45 +0900 Subject: [PATCH 53/66] =?UTF-8?q?feat:=20BusinessException=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/common/exception/BusinessException.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/common/exception/BusinessException.java diff --git a/BE/error/src/main/java/com/example/demo/common/exception/BusinessException.java b/BE/error/src/main/java/com/example/demo/common/exception/BusinessException.java new file mode 100644 index 00000000..899f7570 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/common/exception/BusinessException.java @@ -0,0 +1,16 @@ +package com.example.demo.common.exception; + +import jakarta.persistence.GeneratedValue; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public class BusinessException extends RuntimeException { + private final String code; + private final HttpStatus httpStatus; + + public BusinessException(String code, HttpStatus httpStatus) { + this.code = code; + this.httpStatus = httpStatus; + } +} From 5d2b0b15c8b94952fe88ac7a6035e45053a31a25 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:01:41 +0900 Subject: [PATCH 54/66] =?UTF-8?q?feat:=20CookieManager=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/common/support/CookieManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/common/support/CookieManager.java diff --git a/BE/error/src/main/java/com/example/demo/common/support/CookieManager.java b/BE/error/src/main/java/com/example/demo/common/support/CookieManager.java new file mode 100644 index 00000000..2bfe2bd7 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/common/support/CookieManager.java @@ -0,0 +1,9 @@ +package com.example.demo.common.support; + +import org.springframework.http.ResponseCookie; + +public interface CookieManager { + ResponseCookie setCookie(String key, String value); + + ResponseCookie deleteCookie(String key); +} \ No newline at end of file From 302077be2c186841eec172a586a6545d3c1edd99 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:02:04 +0900 Subject: [PATCH 55/66] =?UTF-8?q?feat:=20TimeUtil=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/common/utils/TimeUtil.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/common/utils/TimeUtil.java diff --git a/BE/error/src/main/java/com/example/demo/common/utils/TimeUtil.java b/BE/error/src/main/java/com/example/demo/common/utils/TimeUtil.java new file mode 100644 index 00000000..7e6b7fb4 --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/common/utils/TimeUtil.java @@ -0,0 +1,9 @@ +package com.example.demo.common.utils; + +public class TimeUtil { + private TimeUtil() {} + + public static int convertSecondsFromMillis(long milliseconds) { + return (int) (milliseconds / 1000); + } +} \ No newline at end of file From 58530b9eef96c0b984e46819f7ae11812726869e Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:02:42 +0900 Subject: [PATCH 56/66] =?UTF-8?q?feat:=20Property=20Config=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/config/PropertyConfig.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/config/PropertyConfig.java diff --git a/BE/error/src/main/java/com/example/demo/config/PropertyConfig.java b/BE/error/src/main/java/com/example/demo/config/PropertyConfig.java new file mode 100644 index 00000000..0f077f7e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/config/PropertyConfig.java @@ -0,0 +1,12 @@ +package com.example.demo.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; + +@Configuration +@PropertySources({ + @PropertySource("classpath:/env.properties") +}) +public class PropertyConfig { +} From 8eee977d020074aab6545c3a1e40f07a53c17472 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:03:04 +0900 Subject: [PATCH 57/66] =?UTF-8?q?feat:=20redis=20config=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/config/RedisConfig.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 BE/error/src/main/java/com/example/demo/config/RedisConfig.java diff --git a/BE/error/src/main/java/com/example/demo/config/RedisConfig.java b/BE/error/src/main/java/com/example/demo/config/RedisConfig.java new file mode 100644 index 00000000..4a47a18e --- /dev/null +++ b/BE/error/src/main/java/com/example/demo/config/RedisConfig.java @@ -0,0 +1,33 @@ +package com.example.demo.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + + +@Configuration +public class RedisConfig { + + @Value("${spring.data.redis.host}") + private String host; + + @Value("${spring.data.redis.port}") + private int port; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + //redisTemplate.setEnableTransactionSupport(true); + + return redisTemplate; + } +} \ No newline at end of file From 3be72a861a40a97cc39891ae9811609f55fe6af6 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:03:59 +0900 Subject: [PATCH 58/66] =?UTF-8?q?fix:=20entity=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/schedule/persistence/ScheduleEntity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/schedule/persistence/ScheduleEntity.java b/BE/error/src/main/java/com/example/demo/schedule/persistence/ScheduleEntity.java index f1698ed0..2fefd276 100644 --- a/BE/error/src/main/java/com/example/demo/schedule/persistence/ScheduleEntity.java +++ b/BE/error/src/main/java/com/example/demo/schedule/persistence/ScheduleEntity.java @@ -13,10 +13,10 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @ToString @Entity -@SuperBuilder(toBuilder = true) // TODO what is the superbuilder?? +@SuperBuilder(toBuilder = true) @Table(name = "Schedule") @EntityListeners(AuditingEntityListener.class) -public class ScheduleEntity extends BaseEntity { // ScheduleEntity에서 BaseEntity를 extends하지 않으면 왜 ScheduleEntityConverter 여기서 에러가 발생했는지 애하가 잘 안가네 +public class ScheduleEntity extends BaseEntity { @Id @GeneratedValue From 05d9f8bac8448a8a59cf6ed63fa0cef1f952e634 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:04:48 +0900 Subject: [PATCH 59/66] =?UTF-8?q?fix:=20=EC=A1=B0=ED=9A=8C=20url=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/schedule/presentation/ScheduleController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BE/error/src/main/java/com/example/demo/schedule/presentation/ScheduleController.java b/BE/error/src/main/java/com/example/demo/schedule/presentation/ScheduleController.java index 8fadc3d8..4775c188 100644 --- a/BE/error/src/main/java/com/example/demo/schedule/presentation/ScheduleController.java +++ b/BE/error/src/main/java/com/example/demo/schedule/presentation/ScheduleController.java @@ -35,15 +35,16 @@ public ApiResponse> create( return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.CREATE); } + @GetMapping("/{eventId}") - public ApiResponse> getSpecificCalendar ( + public ApiResponse> getSpecificCalendar( @PathVariable("eventId") Long eventId ) { SpecificScheduleResopnse response = getSpecificScheduleUsecase.getSpecificSchedule(eventId); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.GET); } - @GetMapping("all/{year}-{month}-{day}") + @GetMapping("all") public ApiResponse>> getAllCalendar() { List response = getAllScheduleUsecase.getAllSchedule(); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.GETALL); From fade7fae6607e99b6cd3902998d88c9b3cf9b016 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:05:35 +0900 Subject: [PATCH 60/66] =?UTF-8?q?feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/error/src/main/java/com/example/demo/ErrorApplication.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BE/error/src/main/java/com/example/demo/ErrorApplication.java b/BE/error/src/main/java/com/example/demo/ErrorApplication.java index 98f0f92b..f23919f2 100644 --- a/BE/error/src/main/java/com/example/demo/ErrorApplication.java +++ b/BE/error/src/main/java/com/example/demo/ErrorApplication.java @@ -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; @@ -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) { From 9dfcd922b59e699c95f93b01666a32b0c11f6663 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:09:01 +0900 Subject: [PATCH 61/66] =?UTF-8?q?fix:=20=EC=84=A4=EC=A0=95=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.properties | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/BE/error/src/main/resources/application.properties b/BE/error/src/main/resources/application.properties index 3b631dad..ae150eaf 100644 --- a/BE/error/src/main/resources/application.properties +++ b/BE/error/src/main/resources/application.properties @@ -1,6 +1,14 @@ spring.jpa.hibernate.ddl-auto=update -spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/example?serverTimezone=Asia/Seoul&characterEncoding=UTF-8 -spring.datasource.username=user -spring.datasource.password=UserPassword +spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/error?serverTimezone=Asia/Seoul&characterEncoding=UTF-8 +spring.datasource.username=root +spring.datasource.password=0012 +spring.profiles.include=token,ouath spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect -cors.allow-origin.urls=https://econo-calendar.com, http://localhost:5173 \ No newline at end of file +cors.allow-origin.urls=https://econo-calendar.com, http://localhost:5173 +spring.config.activate.on-profile.oauth.provider.slack.clientId=437291124342.7141431332214 +spring.config.activate.on-profile.oauth.provider.slack.cliientSecret=b7ea56364590159cd00916bd9e03bec3 +spring.data.redis.host=redis +spring.data.redis.port=6379 + + + From eab3f87d4d749ebca8b0ce578efdc8ae7d7200e9 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:09:48 +0900 Subject: [PATCH 62/66] =?UTF-8?q?feat:=20=EC=84=A4=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-token.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 BE/error/src/main/resources/application-token.yml diff --git a/BE/error/src/main/resources/application-token.yml b/BE/error/src/main/resources/application-token.yml new file mode 100644 index 00000000..7d88bbfa --- /dev/null +++ b/BE/error/src/main/resources/application-token.yml @@ -0,0 +1,18 @@ +spring: + config: + activate: + on-profile: token + +security: + jwt: + access: + validTime: ${AT_VALID_TIME} + secretKey: ${AT_TOKEN_SECRET_KEY} + refresh: + validTime: ${RT_VALID_TIME} + secretKey: ${RT_TOKEN_SECRET_KEY} + +token: + cookie: + domain: ${COOKIE_DOMAIN} + path: ${COOKIE_PATH} From ebb2e2a04d99606eb43c92deee2c25fc147fd677 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:09:59 +0900 Subject: [PATCH 63/66] =?UTF-8?q?feat:=20=EC=84=A4=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/error/src/main/resources/application-ouath.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 BE/error/src/main/resources/application-ouath.yml diff --git a/BE/error/src/main/resources/application-ouath.yml b/BE/error/src/main/resources/application-ouath.yml new file mode 100644 index 00000000..c0118d81 --- /dev/null +++ b/BE/error/src/main/resources/application-ouath.yml @@ -0,0 +1,9 @@ +#spring: +# config: +# activate: +# on-profile: oauth +#oauth: +# provider: +# slack: +# clientId: ${SLACK_CLIENT_ID} +# clientSecret: ${SLACK_CLIENT_SECRET} \ No newline at end of file From 44e2a24c588e23a5fd466939000e52f6b417a888 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:10:10 +0900 Subject: [PATCH 64/66] =?UTF-8?q?feat:=20=EC=84=A4=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/error/src/main/resources/env.properties | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 BE/error/src/main/resources/env.properties diff --git a/BE/error/src/main/resources/env.properties b/BE/error/src/main/resources/env.properties new file mode 100644 index 00000000..a683d4a4 --- /dev/null +++ b/BE/error/src/main/resources/env.properties @@ -0,0 +1,6 @@ +AT_TOKEN_SECRET_KEY=erroroverflowsecretekeyerroroverflowsecretekey +RT_TOKEN_SECRET_KEY=erroroverflowsecretekeyerroroverflowsecretekey +AT_VALID_TIME=3600000 +RT_VALID_TIME=26280000 +COOKIE_DOMAIN=localhost +COOKIE_PATH=/ From 6da75ec083a99dd0e1c3aec095ef164c53ea3e32 Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:12:00 +0900 Subject: [PATCH 65/66] =?UTF-8?q?feat:=20=EB=B9=8C=EB=93=9C=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/error/build.gradle | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/BE/error/build.gradle b/BE/error/build.gradle index d4e36b2b..c2d85da1 100644 --- a/BE/error/build.gradle +++ b/BE/error/build.gradle @@ -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' } @@ -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') { From 12d25d1e014ad2de3faba26aa5dd68e9e7f0cd7b Mon Sep 17 00:00:00 2001 From: capDoYeonLee Date: Thu, 18 Jul 2024 21:12:30 +0900 Subject: [PATCH 66/66] =?UTF-8?q?fix:=20monitor=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/error/docker-compose.yml | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/BE/error/docker-compose.yml b/BE/error/docker-compose.yml index a8e53a06..45e1743c 100644 --- a/BE/error/docker-compose.yml +++ b/BE/error/docker-compose.yml @@ -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: . @@ -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: