Skip to content

Commit 020d928

Browse files
[TB -17] 로그아웃과 비밀번호 재설정, 비회원 조회 링크 생성 (#23)
Co-authored-by: baekjaehyuk <bjh010321@naver.com>
1 parent 4b5a664 commit 020d928

File tree

27 files changed

+283
-33
lines changed

27 files changed

+283
-33
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dependencies {
4141
implementation 'com.auth0:java-jwt:4.4.0'
4242
implementation 'com.google.guava:guava:32.1.2-jre'
4343
implementation 'org.springframework.boot:spring-boot-starter-mail'
44+
implementation 'org.springframework.boot:spring-boot-starter-validation'
4445
}
4546

4647
tasks.withType(Test).configureEach {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.ClubAccount_BE.auth.adapter.in.web.logout;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.tags.Tag;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
8+
@Tag(name = "Logout", description = "로그아웃 API")
9+
public interface LogoutApiPresentation {
10+
@Operation(summary = "로그아웃", description = "리프레시 토큰 쿠키를 제거하여 로그아웃합니다.")
11+
void logout(HttpServletRequest request, HttpServletResponse response);
12+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.ClubAccount_BE.auth.adapter.in.web.logout;
2+
3+
import com.ClubAccount_BE.auth.application.port.in.SignOutUseCase;
4+
import jakarta.servlet.http.Cookie;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.http.HttpHeaders;
9+
import org.springframework.http.ResponseCookie;
10+
import org.springframework.web.bind.annotation.PostMapping;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RestController;
13+
14+
import java.util.Arrays;
15+
import java.util.Optional;
16+
17+
@RestController
18+
@RequestMapping("/api/v1/auth")
19+
@RequiredArgsConstructor
20+
public class LogoutController implements LogoutApiPresentation{
21+
22+
private final SignOutUseCase signOutUseCase;
23+
24+
@PostMapping("/logout")
25+
public void logout(HttpServletRequest request, HttpServletResponse response) {
26+
extractRefreshToken(request)
27+
.ifPresent(signOutUseCase::logout);
28+
29+
ResponseCookie deleteCookie = ResponseCookie.from("refreshToken", "")
30+
.httpOnly(true)
31+
.path("/")
32+
.maxAge(0)
33+
.sameSite("Lax")
34+
.secure(true)
35+
.build();
36+
37+
response.addHeader(HttpHeaders.SET_COOKIE, deleteCookie.toString());
38+
}
39+
40+
private Optional<String> extractRefreshToken(HttpServletRequest request) {
41+
return Optional.ofNullable(request.getCookies())
42+
.flatMap(cookies -> Arrays.stream(cookies)
43+
.filter(cookie -> "refreshToken".equals(cookie.getName()))
44+
.map(Cookie::getValue)
45+
.filter(value -> !value.isBlank())
46+
.findFirst()
47+
);
48+
}
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.ClubAccount_BE.auth.adapter.out.persistence;
2+
3+
import com.ClubAccount_BE.auth.adapter.out.persistence.repository.InMemoryTokenRepository;
4+
import com.ClubAccount_BE.auth.application.port.out.DeleteRefreshTokenPort;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
@RequiredArgsConstructor
10+
public class InMemoryDeleteRefreshTokenAdapter implements DeleteRefreshTokenPort {
11+
12+
private final InMemoryTokenRepository tokenRepository;
13+
14+
@Override
15+
public void deleteByRefreshToken(String refreshToken) {
16+
tokenRepository.deleteRefreshToken(refreshToken);
17+
}
18+
}

src/main/java/com/ClubAccount_BE/auth/adapter/out/persistence/repository/InMemoryTokenRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ public void saveRefreshToken(String refreshToken, Long userId) {
2727
public Optional<Long> getByRefreshToken(String refreshToken) {
2828
return Optional.ofNullable(TOKEN_REPOSITORY.getIfPresent(refreshToken));
2929
}
30+
31+
public void deleteRefreshToken(String refreshToken) {
32+
TOKEN_REPOSITORY.invalidate(refreshToken);
33+
}
3034
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.ClubAccount_BE.auth.application.port.in;
2+
3+
public interface SignOutUseCase {
4+
void logout(String refreshToken);
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.ClubAccount_BE.auth.application.port.out;
2+
3+
public interface DeleteRefreshTokenPort {
4+
void deleteByRefreshToken(String refreshToken);
5+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.ClubAccount_BE.auth.application.service;
2+
3+
import com.ClubAccount_BE.auth.application.port.in.SignOutUseCase;
4+
import com.ClubAccount_BE.auth.application.port.out.DeleteRefreshTokenPort;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
8+
9+
@Service
10+
@RequiredArgsConstructor
11+
@Transactional
12+
public class SignOutService implements SignOutUseCase {
13+
14+
private final DeleteRefreshTokenPort deleteRefreshTokenPort;
15+
16+
@Override
17+
public void logout(String refreshToken) {
18+
deleteRefreshTokenPort.deleteByRefreshToken(refreshToken);
19+
}
20+
}

src/main/java/com/ClubAccount_BE/core/config/SecurityConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
4141
API_V1_PREFIX + "/users/sign-up/check-duplicate-auth-id",
4242
API_V1_PREFIX + "/email/send",
4343
API_V1_PREFIX + "/email/verify",
44+
API_V1_PREFIX + "/auth/reset-password",
4445
"/api-docs",
4546
"/swagger-custom-ui.html",
4647
"/v3/api-docs",

src/main/java/com/ClubAccount_BE/core/config/WebConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers)
2222
@Override
2323
public void addCorsMappings(CorsRegistry registry) {
2424
registry.addMapping("/**")
25-
.allowedOrigins("http://localhost:5173")
25+
.allowedOrigins("http://localhost:5173", "http://172.20.10.3:5173")
2626
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
2727
.allowedHeaders("*")
2828
.exposedHeaders("Authorization", "Set-Cookie")

0 commit comments

Comments
 (0)