-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 카카오 OAuth2 기능 추가 * feat: 로그인 기능 추가 * feat: 테스트 전용 PlatformUserProvider 추가 * test: 로그인 관련 테스트시 쿠키를 얻을 수 있는 공용 메서드 추가 * refactor: 패키지명 변경 * feat: 카카오 로그인시, 사이트에 등록된 회원이면 등록된 정보를 반환하고, 아니라면 등록한 후 정보를 반환하는 기능 추가 * refactor: 팀 컨벤션에 맞게 리팩터링 * test: platformId를 통해 유저를 반환하는 테스트 추가 * refactor: 멤버 생성자 수정으로 인한 테스트 코드 변경 * feat: 가입된 유저라면 201 OK 반환, 가입되지 않은 유저라면 302 FOUND 반환 * refactor: 팀원 피드백 반영 * feat: 로그아웃 기능 추가 * feat: 카카오 로그인 환경 변수 설정
- Loading branch information
Showing
32 changed files
with
894 additions
and
51 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
backend/src/main/java/com/funeat/auth/application/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.funeat.auth.application; | ||
|
||
import com.funeat.auth.dto.SignUserDto; | ||
import com.funeat.auth.dto.UserInfoDto; | ||
import com.funeat.auth.util.PlatformUserProvider; | ||
import com.funeat.member.application.MemberService; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
public class AuthService { | ||
|
||
private final MemberService memberService; | ||
private final PlatformUserProvider platformUserProvider; | ||
|
||
public AuthService(final MemberService memberService, final PlatformUserProvider platformUserProvider) { | ||
this.memberService = memberService; | ||
this.platformUserProvider = platformUserProvider; | ||
} | ||
|
||
public SignUserDto loginWithKakao(final String code) { | ||
final UserInfoDto userInfoDto = platformUserProvider.getPlatformUser(code); | ||
final SignUserDto signUserDto = memberService.findOrCreateMember(userInfoDto); | ||
return signUserDto; | ||
} | ||
|
||
public String getLoginRedirectUri() { | ||
return platformUserProvider.getRedirectURI(); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
backend/src/main/java/com/funeat/auth/dto/KakaoTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.funeat.auth.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public class KakaoTokenDto { | ||
|
||
private final String accessToken; | ||
private final String tokenType; | ||
private final String refreshToken; | ||
private final String expiresIn; | ||
private final String scope; | ||
private final String refreshTokenExpiresIn; | ||
|
||
@JsonCreator | ||
public KakaoTokenDto(@JsonProperty("access_token") final String accessToken, | ||
@JsonProperty("token_type") final String tokenType, | ||
@JsonProperty("refresh_token") final String refreshToken, | ||
@JsonProperty("expires_in") final String expiresIn, | ||
@JsonProperty("scope") final String scope, | ||
@JsonProperty("refresh_token_expires_in") final String refreshTokenExpiresIn) { | ||
this.accessToken = accessToken; | ||
this.tokenType = tokenType; | ||
this.refreshToken = refreshToken; | ||
this.expiresIn = expiresIn; | ||
this.scope = scope; | ||
this.refreshTokenExpiresIn = refreshTokenExpiresIn; | ||
} | ||
|
||
public String getAccessToken() { | ||
return accessToken; | ||
} | ||
|
||
public String getTokenType() { | ||
return tokenType; | ||
} | ||
|
||
public String getRefreshToken() { | ||
return refreshToken; | ||
} | ||
|
||
public String getExpiresIn() { | ||
return expiresIn; | ||
} | ||
|
||
public String getScope() { | ||
return scope; | ||
} | ||
|
||
public String getRefreshTokenExpiresIn() { | ||
return refreshTokenExpiresIn; | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
backend/src/main/java/com/funeat/auth/dto/KakaoUserInfoDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.funeat.auth.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public class KakaoUserInfoDto { | ||
|
||
private final Long id; | ||
private final KakaoAccount kakaoAccount; | ||
|
||
@JsonCreator | ||
public KakaoUserInfoDto(@JsonProperty("id") final Long id, | ||
@JsonProperty("kakao_account") final KakaoAccount kakaoAccount) { | ||
this.id = id; | ||
this.kakaoAccount = kakaoAccount; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public KakaoAccount getKakaoAccount() { | ||
return kakaoAccount; | ||
} | ||
|
||
public static class KakaoAccount { | ||
|
||
private final KakaoProfile profile; | ||
|
||
@JsonCreator | ||
public KakaoAccount(@JsonProperty("profile") final KakaoProfile profile) { | ||
this.profile = profile; | ||
} | ||
|
||
public KakaoProfile getProfile() { | ||
return profile; | ||
} | ||
} | ||
|
||
public static class KakaoProfile { | ||
|
||
private final String nickname; | ||
private final String profileImageUrl; | ||
|
||
@JsonCreator | ||
public KakaoProfile( | ||
@JsonProperty("nickname") final String nickname, | ||
@JsonProperty("profile_image_url") final String profileImageUrl) { | ||
this.nickname = nickname; | ||
this.profileImageUrl = profileImageUrl; | ||
} | ||
|
||
public String getNickname() { | ||
return nickname; | ||
} | ||
|
||
public String getProfileImageUrl() { | ||
return profileImageUrl; | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
backend/src/main/java/com/funeat/auth/dto/LoginRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.funeat.auth.dto; | ||
|
||
public class LoginRequest { | ||
|
||
private final Long id; | ||
|
||
public LoginRequest(final Long id) { | ||
this.id = id; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
backend/src/main/java/com/funeat/auth/dto/SignUserDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.funeat.auth.dto; | ||
|
||
import com.funeat.member.domain.Member; | ||
|
||
public class SignUserDto { | ||
|
||
private final boolean isSignIn; | ||
private final Member member; | ||
|
||
public SignUserDto(final boolean isSignIn, final Member member) { | ||
this.isSignIn = isSignIn; | ||
this.member = member; | ||
} | ||
|
||
public static SignUserDto of(final boolean isSignIn, final Member member) { | ||
return new SignUserDto(isSignIn, member); | ||
} | ||
|
||
public boolean isSignIn() { | ||
return isSignIn; | ||
} | ||
|
||
public Member getMember() { | ||
return member; | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
backend/src/main/java/com/funeat/auth/dto/TokenResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.funeat.auth.dto; | ||
|
||
public class TokenResponse { | ||
|
||
private String accessToken; | ||
|
||
public TokenResponse(final String accessToken) { | ||
this.accessToken = accessToken; | ||
} | ||
|
||
public String getAccessToken() { | ||
return accessToken; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
backend/src/main/java/com/funeat/auth/dto/UserInfoDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.funeat.auth.dto; | ||
|
||
import com.funeat.member.domain.Member; | ||
|
||
public class UserInfoDto { | ||
|
||
private final Long id; | ||
private final String nickname; | ||
private final String profileImageUrl; | ||
|
||
public UserInfoDto(final Long id, final String nickname, final String profileImageUrl) { | ||
this.id = id; | ||
this.nickname = nickname; | ||
this.profileImageUrl = profileImageUrl; | ||
} | ||
|
||
public static UserInfoDto from(final KakaoUserInfoDto kakaoUserInfoDto) { | ||
return new UserInfoDto( | ||
kakaoUserInfoDto.getId(), | ||
kakaoUserInfoDto.getKakaoAccount().getProfile().getNickname(), | ||
kakaoUserInfoDto.getKakaoAccount().getProfile().getProfileImageUrl() | ||
); | ||
} | ||
|
||
public Member toMember() { | ||
return new Member(this.nickname, this.profileImageUrl, this.id.toString()); | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getNickname() { | ||
return nickname; | ||
} | ||
|
||
public String getProfileImageUrl() { | ||
return profileImageUrl; | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
backend/src/main/java/com/funeat/auth/presentation/AuthController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.funeat.auth.presentation; | ||
|
||
import com.funeat.auth.application.AuthService; | ||
import com.funeat.auth.dto.LoginRequest; | ||
import com.funeat.auth.dto.SignUserDto; | ||
import com.funeat.auth.util.AuthenticationPrincipal; | ||
import java.net.URI; | ||
import javax.servlet.http.HttpServletRequest; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
public class AuthController { | ||
|
||
private final AuthService authService; | ||
|
||
public AuthController(final AuthService authService) { | ||
this.authService = authService; | ||
} | ||
|
||
@GetMapping("/api/auth/kakao") | ||
public ResponseEntity<Void> kakaoLogin() { | ||
return ResponseEntity.status(HttpStatus.FOUND) | ||
.location(URI.create(authService.getLoginRedirectUri())) | ||
.build(); | ||
} | ||
|
||
@GetMapping("/login/oauth2/code/kakao") | ||
public ResponseEntity<Void> loginAuthorizeUser(@RequestParam("code") final String code, | ||
final HttpServletRequest request) { | ||
final SignUserDto signUserDto = authService.loginWithKakao(code); | ||
final Long memberId = signUserDto.getMember().getId(); | ||
request.getSession().setAttribute("member", memberId); | ||
|
||
if (signUserDto.isSignIn()) { | ||
return ResponseEntity.status(HttpStatus.FOUND) | ||
.location(URI.create("/")) | ||
.build(); | ||
} | ||
return ResponseEntity.status(HttpStatus.FOUND) | ||
.location(URI.create("/profile")) | ||
.build(); | ||
} | ||
|
||
@GetMapping("/api/logout") | ||
public ResponseEntity<Void> logout(@AuthenticationPrincipal final LoginRequest loginRequest, | ||
final HttpServletRequest request) { | ||
request.getSession().removeAttribute("member"); | ||
|
||
return ResponseEntity.ok().build(); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
backend/src/main/java/com/funeat/auth/util/AuthArgumentResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.funeat.auth.util; | ||
|
||
import com.funeat.auth.dto.LoginRequest; | ||
import java.util.Objects; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpSession; | ||
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 | ||
public class AuthArgumentResolver implements HandlerMethodArgumentResolver { | ||
|
||
@Override | ||
public boolean supportsParameter(MethodParameter parameter) { | ||
return parameter.hasParameterAnnotation(AuthenticationPrincipal.class); | ||
} | ||
|
||
@Override | ||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, | ||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { | ||
final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); | ||
final HttpSession session = Objects.requireNonNull(request).getSession(); | ||
final String id = String.valueOf(session.getAttribute("member")); | ||
|
||
return new LoginRequest(Long.valueOf(id)); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
backend/src/main/java/com/funeat/auth/util/AuthHandlerInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.funeat.auth.util; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import javax.servlet.http.HttpSession; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
|
||
@Component | ||
public class AuthHandlerInterceptor implements HandlerInterceptor { | ||
|
||
@Override | ||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { | ||
final HttpSession session = request.getSession(); | ||
if (session.getAttribute("member") == null) { | ||
throw new IllegalArgumentException("login error"); | ||
} | ||
return true; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
backend/src/main/java/com/funeat/auth/util/AuthenticationPrincipal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.funeat.auth.util; | ||
|
||
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 AuthenticationPrincipal { | ||
} |
Oops, something went wrong.