Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions src/main/java/flipnote/user/auth/application/OAuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import flipnote.user.user.domain.User;
import flipnote.user.user.domain.UserErrorCode;
import flipnote.user.user.domain.UserRepository;
import jakarta.servlet.http.HttpServletRequest;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseCookie;
Expand Down Expand Up @@ -43,8 +43,7 @@ public record AuthorizationRedirect(String authorizeUri, ResponseCookie verifier

private static final int VERIFIER_COOKIE_MAX_AGE = 180;

public AuthorizationRedirect getAuthorizationUri(String providerName, HttpServletRequest request,
Long userId) {
public AuthorizationRedirect getAuthorizationUri(String providerName, Long userId) {
OAuthProperties.Provider provider = resolveProvider(providerName);

String codeVerifier = pkceUtil.generateCodeVerifier();
Expand All @@ -56,7 +55,7 @@ public AuthorizationRedirect getAuthorizationUri(String providerName, HttpServle
socialLinkTokenRepository.save(userId, state);
}

String authorizeUri = oAuthApiClient.buildAuthorizeUri(request, provider, codeChallenge, state);
String authorizeUri = oAuthApiClient.buildAuthorizeUri(provider, codeChallenge, state);

ResponseCookie verifierCookie = ResponseCookie.from(HttpConstants.OAUTH_VERIFIER_COOKIE, codeVerifier)
.httpOnly(true)
Expand All @@ -69,9 +68,8 @@ public AuthorizationRedirect getAuthorizationUri(String providerName, HttpServle
return new AuthorizationRedirect(authorizeUri, verifierCookie);
}

public TokenPair socialLogin(String providerName, String code, String codeVerifier,
HttpServletRequest request) {
OAuth2UserInfo userInfo = getOAuth2UserInfo(providerName, code, codeVerifier, request);
public TokenPair socialLogin(String providerName, String code, String codeVerifier) {
OAuth2UserInfo userInfo = getOAuth2UserInfo(providerName, code, codeVerifier);

OAuthLink oAuthLink = oAuthLinkRepository
.findByProviderAndProviderIdWithUser(userInfo.getProvider(), userInfo.getProviderId())
Expand All @@ -82,13 +80,13 @@ public TokenPair socialLogin(String providerName, String code, String codeVerifi

@Transactional
public void linkSocialAccount(String providerName, String code, String state,
String codeVerifier, HttpServletRequest request) {
String codeVerifier) {
Long userId = socialLinkTokenRepository.findUserIdByState(state)
.orElseThrow(() -> new BizException(AuthErrorCode.INVALID_SOCIAL_LINK_TOKEN));

socialLinkTokenRepository.delete(state);

OAuth2UserInfo userInfo = getOAuth2UserInfo(providerName, code, codeVerifier, request);
OAuth2UserInfo userInfo = getOAuth2UserInfo(providerName, code, codeVerifier);

if (oAuthLinkRepository.existsByUser_IdAndProviderAndProviderId(
userId, userInfo.getProvider(), userInfo.getProviderId())) {
Expand All @@ -107,9 +105,9 @@ public void linkSocialAccount(String providerName, String code, String state,
}

private OAuth2UserInfo getOAuth2UserInfo(String providerName, String code,
String codeVerifier, HttpServletRequest request) {
String codeVerifier) {
OAuthProperties.Provider provider = resolveProvider(providerName);
String accessToken = oAuthApiClient.requestAccessToken(provider, code, codeVerifier, request);
String accessToken = oAuthApiClient.requestAccessToken(provider, code, codeVerifier);
Map<String, Object> attributes = oAuthApiClient.requestUserInfo(provider, accessToken);
return oAuthApiClient.createUserInfo(providerName, attributes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClient;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;

import flipnote.user.global.config.OAuthProperties;
import jakarta.servlet.http.HttpServletRequest;

import lombok.RequiredArgsConstructor;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.ObjectMapper;
Expand All @@ -23,14 +22,15 @@ public class OAuthApiClient {

private final RestClient restClient;
private final ObjectMapper objectMapper;
private final OAuthProperties oAuthProperties;

public String requestAccessToken(OAuthProperties.Provider provider, String code,
String codeVerifier, HttpServletRequest request) {
String codeVerifier) {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", provider.getClientId());
params.add("client_secret", provider.getClientSecret());
params.add("redirect_uri", buildRedirectUri(request, provider.getRedirectUri()));
params.add("redirect_uri", buildRedirectUri(provider.getRedirectUri()));
params.add("code", code);
params.add("code_verifier", codeVerifier);

Expand Down Expand Up @@ -70,11 +70,11 @@ public OAuth2UserInfo createUserInfo(String providerName, Map<String, Object> at
};
}

public String buildAuthorizeUri(HttpServletRequest request, OAuthProperties.Provider provider,
public String buildAuthorizeUri(OAuthProperties.Provider provider,
String codeChallenge, String state) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(provider.getAuthorizationUri())
.queryParam("client_id", provider.getClientId())
.queryParam("redirect_uri", buildRedirectUri(request, provider.getRedirectUri()))
.queryParam("redirect_uri", buildRedirectUri(provider.getRedirectUri()))
.queryParam("response_type", "code")
.queryParam("scope", String.join(" ", provider.getScope()))
.queryParam("code_challenge", codeChallenge)
Expand All @@ -87,9 +87,9 @@ public String buildAuthorizeUri(HttpServletRequest request, OAuthProperties.Prov
return builder.toUriString();
}

private String buildRedirectUri(HttpServletRequest request, String path) {
return ServletUriComponentsBuilder.fromRequestUri(request)
.replacePath(path)
private String buildRedirectUri(String path) {
return UriComponentsBuilder.fromUriString(oAuthProperties.getBaseUrl())
.path(path)
.build()
.toUriString();
}
Expand Down
19 changes: 8 additions & 11 deletions src/main/java/flipnote/user/auth/presentation/OAuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import flipnote.user.global.constants.HttpConstants;
import flipnote.user.global.util.CookieUtil;
import flipnote.user.auth.infrastructure.jwt.JwtProvider;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -32,9 +31,8 @@ public class OAuthController {
@GetMapping("/oauth2/authorization/{provider}")
public ResponseEntity<Void> redirectToProvider(
@PathVariable String provider,
@RequestHeader(value = HttpConstants.USER_ID_HEADER, required = false) Long userId,
HttpServletRequest request) {
OAuthService.AuthorizationRedirect redirect = oAuthService.getAuthorizationUri(provider, request, userId);
@RequestHeader(value = HttpConstants.USER_ID_HEADER, required = false) Long userId) {
OAuthService.AuthorizationRedirect redirect = oAuthService.getAuthorizationUri(provider, userId);

return ResponseEntity.status(HttpStatus.FOUND)
.header(HttpHeaders.SET_COOKIE, redirect.verifierCookie().toString())
Expand All @@ -48,22 +46,21 @@ public ResponseEntity<Void> handleCallback(
@RequestParam String code,
@RequestParam(required = false) String state,
@CookieValue(HttpConstants.OAUTH_VERIFIER_COOKIE) String codeVerifier,
HttpServletRequest request,
HttpServletResponse response) {

CookieUtil.deleteCookie(response, HttpConstants.OAUTH_VERIFIER_COOKIE);

boolean isSocialLinkRequest = StringUtils.hasText(state);
if (isSocialLinkRequest) {
return handleSocialLink(provider, code, state, codeVerifier, request);
return handleSocialLink(provider, code, state, codeVerifier);
}
return handleSocialLogin(provider, code, codeVerifier, request, response);
return handleSocialLogin(provider, code, codeVerifier, response);
}

private ResponseEntity<Void> handleSocialLogin(String provider, String code, String codeVerifier,
HttpServletRequest request, HttpServletResponse response) {
HttpServletResponse response) {
try {
TokenPair tokenPair = oAuthService.socialLogin(provider, code, codeVerifier, request);
TokenPair tokenPair = oAuthService.socialLogin(provider, code, codeVerifier);
CookieUtil.addCookie(response, HttpConstants.ACCESS_TOKEN_COOKIE, tokenPair.accessToken(),
jwtProvider.getAccessTokenExpiration() / 1000);
CookieUtil.addCookie(response, HttpConstants.REFRESH_TOKEN_COOKIE, tokenPair.refreshToken(),
Expand All @@ -80,9 +77,9 @@ private ResponseEntity<Void> handleSocialLogin(String provider, String code, Str
}

private ResponseEntity<Void> handleSocialLink(String provider, String code, String state,
String codeVerifier, HttpServletRequest request) {
String codeVerifier) {
try {
oAuthService.linkSocialAccount(provider, code, state, codeVerifier, request);
oAuthService.linkSocialAccount(provider, code, state, codeVerifier);
return ResponseEntity.status(HttpStatus.FOUND)
.location(URI.create(clientProperties.getUrl() + clientProperties.getPaths().getSocialLinkSuccess()))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@ConfigurationProperties(prefix = "app.oauth2")
public class OAuthProperties {

private final String baseUrl;
private final Map<String, Provider> providers;

@Getter
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ app:
social-login-success: /social-login/success
social-login-failure: /social-login/failure
oauth2:
base-url: ${OAUTH_BASE_URL:https://api3.flipnote.site}
providers:
google:
client-id: ${GOOGLE_CLIENT_ID:}
Expand Down
Loading