-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] feat: 카카오 로그인 기능을 추가 #123
Conversation
backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java
Show resolved
Hide resolved
02f1d28
to
d2433b8
Compare
5700df6
to
a1d89a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어려운 기능 구현하느라 고생했어요 🥲
몇 가지 작은 수정 사항들이랑 코멘트 남겼습니다!
backend/src/main/java/com/funeat/auth/application/AuthService.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/com/funeat/member/persistence/MemberRepository.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/com/funeat/acceptance/common/TestPlatformUserProvider.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
너무 멋져요 로건..👍
backend/src/main/java/com/funeat/auth/application/AuthService.java
Outdated
Show resolved
Hide resolved
af8bf68
to
b32f4f7
Compare
@WebMvcTest(AuthController.class) | ||
@SuppressWarnings("NonAsciiCharacters") | ||
public class AuthControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockBean | ||
private AuthService authService; | ||
|
||
@Nested | ||
class loginAuthorizeUser_테스트 { | ||
|
||
@Test | ||
void 이미_가입된_유저라면_홈_경로로_리다이렉트한다() throws Exception { | ||
// given | ||
final var code = "test"; | ||
final var member = new Member("test", "www.test.com", "1"); | ||
final var signUserDto = SignUserDto.of(true, member); | ||
|
||
// when | ||
when(authService.loginWithKakao(code)).thenReturn(signUserDto); | ||
|
||
// then | ||
mockMvc.perform(get("/login/oauth2/code/kakao") | ||
.param("code", code)) | ||
.andExpect(status().isFound()) | ||
.andExpect(redirectedUrl("/")); | ||
} | ||
|
||
@Test | ||
void 가입되지_않은_유저라면_프로필_경로로_리다이렉트한다() throws Exception { | ||
// given | ||
final var code = "test"; | ||
final var member = new Member("test", "www.test.com", "1"); | ||
final var signUserDto = SignUserDto.of(false, member); | ||
|
||
// when | ||
when(authService.loginWithKakao(code)).thenReturn(signUserDto); | ||
|
||
// then | ||
mockMvc.perform(get("/login/oauth2/code/kakao") | ||
.param("code", code)) | ||
.andExpect(status().isFound()) | ||
.andExpect(redirectedUrl("/profile")); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 이유라면 테스트 작성 안하는 것보다는 MockMvc로 테스트 하는 게 맞다고 생각합니다! 굿굿
final HttpSession session = request.getSession(); | ||
if (session.getAttribute("member") == null) { | ||
throw new IllegalArgumentException("login error"); | ||
} | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
쉐도우 복싱입니다.
- 이미 서버 세션에는 member 정보가 남아있습니다.
- 클라이언트는 로그인이 되어있지 않은 사용자가 로그인이 필요한 서비스를 이용하려고 할때,
해당 부분 분기에서 login error 가 뜨지 않고 넘어갈 것 같습니다.
backend/src/main/java/com/funeat/auth/util/KakaoPlatformUserProvider.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/com/funeat/member/application/MemberService.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로그인이 로거인이 됐네요 정말 수고 많으셨어요!!! 🙇♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
소셜 로그인 테스트.. 멋져요..👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로그인.. 확실히 복잡하네요..
고생하셨습니다~!
@WebMvcTest(AuthController.class) | ||
@SuppressWarnings("NonAsciiCharacters") | ||
public class AuthControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockBean | ||
private AuthService authService; | ||
|
||
@Nested | ||
class loginAuthorizeUser_테스트 { | ||
|
||
@Test | ||
void 이미_가입된_유저라면_홈_경로로_리다이렉트한다() throws Exception { | ||
// given | ||
final var code = "test"; | ||
final var member = new Member("test", "www.test.com", "1"); | ||
final var signUserDto = SignUserDto.of(true, member); | ||
|
||
// when | ||
when(authService.loginWithKakao(code)).thenReturn(signUserDto); | ||
|
||
// then | ||
mockMvc.perform(get("/login/oauth2/code/kakao") | ||
.param("code", code)) | ||
.andExpect(status().isFound()) | ||
.andExpect(redirectedUrl("/")); | ||
} | ||
|
||
@Test | ||
void 가입되지_않은_유저라면_프로필_경로로_리다이렉트한다() throws Exception { | ||
// given | ||
final var code = "test"; | ||
final var member = new Member("test", "www.test.com", "1"); | ||
final var signUserDto = SignUserDto.of(false, member); | ||
|
||
// when | ||
when(authService.loginWithKakao(code)).thenReturn(signUserDto); | ||
|
||
// then | ||
mockMvc.perform(get("/login/oauth2/code/kakao") | ||
.param("code", code)) | ||
.andExpect(status().isFound()) | ||
.andExpect(redirectedUrl("/profile")); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 이유라면 테스트 작성 안하는 것보다는 MockMvc로 테스트 하는 게 맞다고 생각합니다! 굿굿
세션은
세션을 가져올 때에는 @Override
public Session findSession(String id) throws IOException {
if (id == null) {
return null;
}
return sessions.get(id);
} 이제 실제로 세션을 가져오는 것은 확인하는 것은 public Session getSessionInternal() {
return doGetSession(true);
} protected Session doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
Context context = getContext();
if (context == null) {
return null;
}
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
return session;
}
// Return the requested session if it exists and is valid
Manager manager = context.getManager();
if (manager == null) {
return null; // Sessions are not supported
}
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("request.session.failed", requestedSessionId, e.getMessage()), e);
} else {
log.info(sm.getString("request.session.failed", requestedSessionId, e.getMessage()));
}
session = null;
}
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
session.access();
return session;
}
}
// Create a new session if requested and the response is not committed
if (!create) {
return null;
}
boolean trackModesIncludesCookie =
context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE);
if (trackModesIncludesCookie && response.getResponse().isCommitted()) {
throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));
}
// Re-use session IDs provided by the client in very limited
// circumstances.
String sessionId = getRequestedSessionId();
if (requestedSessionSSL) {
// If the session ID has been obtained from the SSL handshake then
// use it.
} else if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie())) {
/*
* This is the common(ish) use case: using the same session ID with multiple web applications on the same
* host. Typically this is used by Portlet implementations. It only works if sessions are tracked via
* cookies. The cookie must have a path of "/" else it won't be provided for requests to all web
* applications.
*
* Any session ID provided by the client should be for a session that already exists somewhere on the host.
* Check if the context is configured for this to be confirmed.
*/
if (context.getValidateClientProvidedNewSessionId()) {
boolean found = false;
for (Container container : getHost().findChildren()) {
Manager m = ((Context) container).getManager();
if (m != null) {
try {
if (m.findSession(sessionId) != null) {
found = true;
break;
}
} catch (IOException e) {
// Ignore. Problems with this manager will be
// handled elsewhere.
}
}
}
if (!found) {
sessionId = null;
}
}
} else {
sessionId = null;
}
session = manager.createSession(sessionId);
// Creating a new session cookie based on that session
if (session != null && trackModesIncludesCookie) {
Cookie cookie =
ApplicationSessionCookieConfig.createSessionCookie(context, session.getIdInternal(), isSecure());
response.addSessionCookieInternal(cookie);
}
if (session == null) {
return null;
}
session.access();
return session;
} 이쪽에서 try - catch문을 벗어나면 이제 새로운 세션을 생성하는 일이에요. 그래서 클라이언트가 쿠키에 저장된 JSESSIONID을 헤더로 보내면 JSESSIONID를 통해 Session 객체를 찾고, Session 객체에 있는 name을 통해 value를 확인하는 과정이 됩니다. |
Issue
✨ 구현한 기능
📢 논의하고 싶은 내용
🎸 기타
RestTemplate vs WebClient
⏰ 일정