Skip to content

Commit 75a88db

Browse files
committed
feat: 자동 로그인 기능 추가 및 리졸버에서 파싱하도록 구현
1 parent 39126d6 commit 75a88db

13 files changed

+277
-26
lines changed

src/main/java/com/example/busan/auth/AuthController.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.example.busan.auth;
22

3+
import com.example.busan.auth.domain.AutoLoginManager;
34
import com.example.busan.auth.dto.AuthenticatePhoneRequest;
45
import com.example.busan.auth.dto.Authentication;
56
import com.example.busan.auth.dto.FindEmailResponse;
67
import com.example.busan.auth.dto.LoginRequest;
78
import com.example.busan.auth.service.AuthService;
89
import com.example.busan.auth.service.PhoneAuthenticator;
10+
import jakarta.servlet.http.HttpServletResponse;
911
import jakarta.servlet.http.HttpSession;
1012
import org.springframework.http.ResponseEntity;
1113
import org.springframework.web.bind.annotation.GetMapping;
@@ -23,15 +25,26 @@ public class AuthController {
2325

2426
private final AuthService authService;
2527
private final PhoneAuthenticator phoneAuthenticator;
28+
private final AutoLoginManager autoLoginManager;
2629

27-
public AuthController(final AuthService authService, final PhoneAuthenticator phoneAuthenticator) {
30+
public AuthController(final AuthService authService,
31+
final PhoneAuthenticator phoneAuthenticator,
32+
AutoLoginManager autoLoginManager) {
2833
this.authService = authService;
2934
this.phoneAuthenticator = phoneAuthenticator;
35+
this.autoLoginManager = autoLoginManager;
3036
}
3137

3238
@PostMapping("/login")
33-
public ResponseEntity<Void> login(@RequestBody final LoginRequest request, final HttpSession session) {
39+
public ResponseEntity<Void> login(@RequestBody final LoginRequest request,
40+
final HttpServletResponse httpServletResponse,
41+
final HttpSession session) {
3442
final Authentication authentication = authService.login(request);
43+
44+
if (request.isAuto()) {
45+
autoLoginManager.setAutoCookie(session, httpServletResponse, authentication);
46+
}
47+
3548
session.setAttribute(AUTHORIZATION, authentication);
3649
return ResponseEntity.noContent().build();
3750
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.example.busan.auth;
22

33
import com.example.busan.auth.domain.Authorized;
4+
import com.example.busan.auth.domain.AutoLoginManager;
45
import com.example.busan.auth.dto.Authentication;
5-
import com.example.busan.auth.exception.UnauthorizedException;
6+
import jakarta.servlet.http.HttpServletRequest;
67
import org.springframework.core.MethodParameter;
78
import org.springframework.stereotype.Component;
89
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -11,12 +12,17 @@
1112
import org.springframework.web.method.support.ModelAndViewContainer;
1213

1314
import static com.example.busan.auth.AuthController.AUTHORIZATION;
14-
import static java.util.Objects.isNull;
1515
import static org.springframework.web.context.request.RequestAttributes.SCOPE_SESSION;
1616

1717
@Component
1818
public class AuthorizationArgumentResolver implements HandlerMethodArgumentResolver {
1919

20+
private final AutoLoginManager autoLoginManager;
21+
22+
public AuthorizationArgumentResolver(AutoLoginManager autoLoginManager) {
23+
this.autoLoginManager = autoLoginManager;
24+
}
25+
2026
@Override
2127
public boolean supportsParameter(final MethodParameter parameter) {
2228
final boolean hasAnnotation = parameter.hasParameterAnnotation(Authorized.class);
@@ -29,12 +35,13 @@ public boolean supportsParameter(final MethodParameter parameter) {
2935
public Object resolveArgument(final MethodParameter parameter,
3036
final ModelAndViewContainer mavContainer,
3137
final NativeWebRequest webRequest,
32-
final WebDataBinderFactory binderFactory) throws Exception {
33-
final Object authentication = webRequest.getAttribute(AUTHORIZATION, SCOPE_SESSION);
34-
if (isNull(authentication)) {
35-
throw new UnauthorizedException();
38+
final WebDataBinderFactory binderFactory) {
39+
Object authentication = webRequest.getAttribute(AUTHORIZATION, SCOPE_SESSION);
40+
if (authentication != null) {
41+
return authentication;
3642
}
3743

38-
return authentication;
44+
final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
45+
return autoLoginManager.getAuthentication(request);
3946
}
4047
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.busan.auth.domain;
2+
3+
import com.example.busan.auth.dto.Authentication;
4+
import jakarta.persistence.Embedded;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.Id;
7+
8+
@Entity
9+
public class AutoLogin {
10+
11+
@Id
12+
private String id;
13+
@Embedded
14+
private Authentication authentication;
15+
16+
protected AutoLogin() {
17+
}
18+
19+
public AutoLogin(final String id, final Authentication authentication) {
20+
this.id = id;
21+
this.authentication = authentication;
22+
}
23+
24+
public String getId() {
25+
return id;
26+
}
27+
28+
public Authentication getAuthentication() {
29+
return authentication;
30+
}
31+
}

src/main/java/com/example/busan/auth/domain/AutoLoginManager.java

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package com.example.busan.auth.domain;
22

3+
import com.example.busan.auth.dto.Authentication;
4+
import com.example.busan.auth.exception.UnauthorizedException;
5+
import jakarta.servlet.http.Cookie;
36
import jakarta.servlet.http.HttpServletRequest;
7+
import jakarta.servlet.http.HttpServletResponse;
8+
import jakarta.servlet.http.HttpSession;
49
import org.springframework.stereotype.Component;
510

611
import java.util.Arrays;
@@ -10,12 +15,56 @@ public class AutoLoginManager {
1015

1116
public static final String AUTO_LOGIN_COOKIE_NAME = "AUTO";
1217

18+
private final AutoLoginRepository autoLoginRepository;
19+
20+
public AutoLoginManager(AutoLoginRepository autoLoginRepository) {
21+
this.autoLoginRepository = autoLoginRepository;
22+
}
23+
1324
public boolean isAuto(final HttpServletRequest request) {
1425
if (request == null) {
1526
return false;
1627
}
1728

1829
return Arrays.stream(request.getCookies())
19-
.anyMatch(cookie -> cookie.getName().equals("AUTO"));
30+
.anyMatch(cookie -> cookie.getName().equals(AUTO_LOGIN_COOKIE_NAME));
31+
}
32+
33+
public void setAutoCookie(final HttpSession httpSession,
34+
final HttpServletResponse response,
35+
final Authentication authentication) {
36+
final String id = httpSession.getId();
37+
38+
autoLoginRepository.save(new AutoLogin(id, authentication));
39+
40+
final Cookie cookie = new Cookie(AUTO_LOGIN_COOKIE_NAME, id);
41+
cookie.setPath("/");
42+
cookie.setMaxAge(Integer.MAX_VALUE);
43+
response.addCookie(cookie);
44+
}
45+
46+
public Authentication getAuthentication(final HttpServletRequest request) {
47+
final Cookie autoLoggedInCookie = getAutoLoggedInCookie(request);
48+
49+
final String id = autoLoggedInCookie.getValue();
50+
return autoLoginRepository.findById(id)
51+
.orElseThrow(UnauthorizedException::new)
52+
.getAuthentication();
53+
}
54+
55+
private Cookie getAutoLoggedInCookie(final HttpServletRequest request) {
56+
return Arrays.stream(request.getCookies())
57+
.filter(cookie -> cookie.getName().equals(AUTO_LOGIN_COOKIE_NAME))
58+
.findAny()
59+
.orElseThrow(UnauthorizedException::new);
60+
}
61+
62+
public void removeAutoLogin(final HttpServletRequest request,
63+
final HttpServletResponse response) {
64+
final Cookie autoLoggedInCookie = getAutoLoggedInCookie(request);
65+
autoLoggedInCookie.setMaxAge(0);
66+
response.addCookie(autoLoggedInCookie);
67+
68+
autoLoginRepository.deleteById(autoLoggedInCookie.getValue());
2069
}
2170
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.example.busan.auth.domain;
2+
3+
import org.springframework.data.jpa.repository.JpaRepository;
4+
5+
public interface AutoLoginRepository extends JpaRepository<AutoLogin, String> {
6+
}

src/main/java/com/example/busan/auth/dto/Authentication.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
import com.example.busan.member.domain.Member;
44
import com.example.busan.member.domain.Role;
5+
import jakarta.persistence.Embeddable;
6+
import jakarta.persistence.EnumType;
7+
import jakarta.persistence.Enumerated;
58

6-
public record Authentication(String email, Role role) {
9+
@Embeddable
10+
public record Authentication(String email, @Enumerated(value = EnumType.STRING) Role role) {
711

812
public static Authentication from(final Member member) {
913
return new Authentication(member.getEmail(), member.getRole());
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package com.example.busan.auth.dto;
22

3-
public record LoginRequest(String email, String password) {
3+
public record LoginRequest(String email, String password, boolean isAuto) {
44
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE auto_login
2+
(
3+
id VARCHAR(40) PRIMARY KEY,
4+
email VARCHAR(255) NOT NULL,
5+
role ENUM ('ADMIN','USER') NOT NULL
6+
);

src/test/java/com/example/busan/DatabaseCleaner.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,29 @@
33
import jakarta.persistence.EntityManager;
44
import jakarta.persistence.PersistenceContext;
55
import jakarta.persistence.Query;
6-
import jakarta.persistence.metamodel.EntityType;
76
import org.springframework.beans.factory.InitializingBean;
87
import org.springframework.stereotype.Component;
98
import org.springframework.transaction.annotation.Transactional;
109

1110
import java.util.List;
12-
import java.util.Set;
1311

1412
@Component
1513
public class DatabaseCleaner implements InitializingBean {
1614

15+
private static final String TRUNCATE = "TRUNCATE ";
16+
private static final String FLYWAY = "flyway";
17+
1718
@PersistenceContext
1819
private EntityManager entityManager;
1920
private List<String> truncateDMLs;
2021

2122
@Override
2223
public void afterPropertiesSet() {
23-
final Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();
24+
final List<String> tableNames = entityManager.createNativeQuery("SHOW TABLES ").getResultList();
2425

25-
truncateDMLs = entities.stream()
26-
.map(entity -> "TRUNCATE " + entity.getName().toLowerCase())
26+
truncateDMLs = tableNames.stream()
27+
.filter(tableName -> !tableName.contains(FLYWAY))
28+
.map(TRUNCATE::concat)
2729
.toList();
2830
}
2931

src/test/java/com/example/busan/auth/AuthControllerTest.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void login() throws Exception {
4848
final Authentication authentication = new Authentication("[email protected]", Role.USER);
4949
given(authService.login(any()))
5050
.willReturn(authentication);
51-
final String request = objectMapper.writeValueAsString(new LoginRequest("[email protected]", "password"));
51+
final String request = objectMapper.writeValueAsString(new LoginRequest("[email protected]", "password", true));
5252

5353
//when
5454
final MockHttpServletResponse response = mockMvc.perform(
@@ -60,7 +60,8 @@ void login() throws Exception {
6060
.andDo(document("로그인 하기",
6161
requestFields(
6262
fieldWithPath("email").description("이메일"),
63-
fieldWithPath("password").description("비밀번호"))))
63+
fieldWithPath("password").description("비밀번호"),
64+
fieldWithPath("isAuto").description("자동 로그인 여부"))))
6465
.andReturn()
6566
.getResponse();
6667

src/test/java/com/example/busan/auth/AuthenticationServiceTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void initDatabase() {
4242
void login() {
4343
//given
4444
final Member member = createMember();
45-
final LoginRequest request = new LoginRequest(member.getEmail(), "@password1234");
45+
final LoginRequest request = new LoginRequest(member.getEmail(), "@password1234", false);
4646

4747
//when
4848
final Authentication login = authService.login(request);
@@ -55,7 +55,7 @@ void login() {
5555
@DisplayName("로그인 실패")
5656
void login_fail() {
5757
//given
58-
final LoginRequest request = new LoginRequest("ididididid", "@password1234");
58+
final LoginRequest request = new LoginRequest("ididididid", "@password1234", false);
5959

6060
//when, then
6161
assertThatThrownBy(() -> authService.login(request))

0 commit comments

Comments
 (0)