๊ฐ์
๊ธฐ์กด ํ์ ํํด ๋ฐฉ์์ ๋จ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํ์ ์ ๋ณด๋ฅผ ์ญ์ ํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ๋ง์ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค. ํ์ง๋ง ๋ณด๋ค ํ์คํ ํํด ์งํ์ ์ํด, ์์ ๋ก๊ทธ์ธ ์ ๊ณต์(`Google`, `Kakao`)์์ ๊ณ์ ์ฐ๊ฒฐ ํด์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ต๋๋ค.
๊ณ์ ์ฐ๊ฒฐ ํด์ ์์ฒญ
Google Developers - revoke ์์ ์ฐ๊ฒฐ ํด์ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
โKakao
Kakao Developers - unlink ์์ ์ฐ๊ฒฐ ํด์ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
Access ํ ํฐ ๋๋ ์ฑ ์ด๋๋ฏผ ํค(`Admin key`)๋ก ์ฐ๊ฒฐ ํด์ API๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ์ฐ๊ฒฐ ๋๊ธฐ ์์ฒญ์ ์ฑ๊ณตํ๋ฉด ํด๋น ์ฌ์ฉ์ ํ์ ๋ฒํธ๋ฅผ ์๋ต์ผ๋ก ๋ฐ๊ณ , ๋ก๊ทธ์์์ด ํจ๊ป ์งํ๋์ด Access ํ ํฐ๊ณผ Refresh ํ ํฐ์ด ๋ง๋ฃ ์ฒ๋ฆฌ๋ฉ๋๋ค.
1๏ธโฃ์ด๋๋ฏผ ํค ์ฌ์ฉ
`Admin key`๋ฅผ ์ฌ์ฉํ๋ REST API ์์ฒญ์ ๋ฐ๋์ ์๋ฒ์์๋ง ์ํํด์ผ ํ๋ฉฐ, ์์ค ์ฝ๋์ ๋ ธ์ถ๋์ง ์๋๋ก ์ฃผ์ํด์ผ ํฉ๋๋ค. ๋ํ, `Admin key`๋ฅผ ์ฌ์ฉํด ์ฐ๊ฒฐ ํด์ ์์ฒญ ์, ๋์ ์ฌ์ฉ์๋ฅผ ๋ช ์ํ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ํจ๊ป ๋ณด๋ด์ผ ํฉ๋๋ค.
2๏ธโฃํ ํฐ ์ฌ์ฉ
`Google`์์๋ `Admin key` ์ฌ์ฉ ๋ฐฉ์์ด ์์ผ๋ฏ๋ก, ์ผ๊ด์ฑ์ ์ํด, ํ ํฐ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก ๊ณ์ ์ฐ๊ฒฐ ํด์ API ํธ์ถ ๋ฐฉ์์ ํต์ผํ์ต๋๋ค.
ํ ํฐ ๊ฐฑ์ ์์ฒญ
Google Developers - token ์์ Access ํ ํฐ ๊ฐฑ์ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
โKakao
Kakao Developers - token ์์ ํ ํฐ ๊ฐฑ์ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
`Kakao`์์๋ `Google`๊ณผ ๋ฌ๋ฆฌ Refresh ํ ํฐ์ด ์กฐ๊ฑด(์ ํจ ๊ธฐ๊ฐ์ด 1๊ฐ์ ๋ฏธ๋ง) ์ถฉ์กฑ ์, Access ํ ํฐ๊ณผ ํจ๊ป ์ฌ๋ฐ๊ธ์ด ๋ ์ ์์ต๋๋ค. ํ์ง๋ง ์ ํฌ ํ๋ก์ ํธ์์๋ ํด๋น Refresh ํ ํฐ ๊ธฐ๊ฐ์ 2์ฃผ๋ก ์ค์ ํ๊ธฐ์, ์ด๋ฌํ ์กฐ๊ฑด์ ๊ณ ๋ คํ์ง ์์๋ ๋ฉ๋๋ค. (2์ฃผ๋ก ์ค์ ํ ์ด์ ๋ ์๋์์ ๋ค์ ์ธ๊ธํ๊ฒ ์ต๋๋ค.)
Spring Cloud OpenFeign
์์ ์ธ๊ธํ ์์ ๋ก๊ทธ์ธ ์ ๊ณต์(`Kakao`, `Google`)์ API๋ฅผ ํธ์ถํ์ฌ ๊ณ์ ์ฐ๊ฒฐ ํด์ ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด `Spring Cloud OpenFeign`์ ์ฌ์ฉํ์ต๋๋ค. OpenFeign์ ์ ์ธํ HTTP ํด๋ผ์ด์ธํธ๋ก, REST API ํธ์ถ ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๊ฒ ์์ฑํ ์ ์๋๋ก ํด์ค๋๋ค.
๊ธฐ๋ณธ ์ค์
- ์์กด์ฑ ์ถ๊ฐ
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.1"
}
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}
- ๊ธฐ๋ฅ ํ์ฑํ
@EnableFeignClients
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
API ํธ์ถ ์ฝ๋
๐ Google
@FeignClient(name = "googleClient", url = "https://oauth2.googleapis.com")
public interface GoogleClient {
// Refresh ํ ํฐ์ ์ฌ์ฉํ ํ ํฐ ์ฌ๋ฐ๊ธ ์์ฒญ
@PostMapping("/token")
TokenResponse reissueToken(
@RequestParam("grant_type") String grantType, // "refresh_token"์ผ๋ก ๊ณ ์
@RequestParam("client_id") String clientId,
@RequestParam("refresh_token") String refreshToken,
@RequestParam("client_secret") String clientSecret
);
// ์ฐ๊ฒฐ ํด์ ์์ฒญ
// Refresh, Access ํ ํฐ ๋ ๋ค ์ฌ์ฉ ๊ฐ๋ฅ
@PostMapping("/revoke")
void unlink(@RequestParam("token") String accessToken);
}
๐ Kakao
@FeignClient(name = "kakaoApiClient", url = "https://kapi.kakao.com")
public interface KakaoApiClient {
// Access ํ ํฐ์ ์ฌ์ฉํ ์ฐ๊ฒฐ ํด์ ์์ฒญ
@PostMapping("/v1/user/unlink")
UnlinkResponse unlink(@RequestHeader("Authorization") String accessToken);
}
@FeignClient(name = "kakaoAuthClient", url = "https://kauth.kakao.com")
public interface KakaoAuthClient {
// Refresh ํ ํฐ์ ์ฌ์ฉํ ํ ํฐ ์ฌ๋ฐ๊ธ ์์ฒญ
@PostMapping("/oauth/token")
TokenResponse reissueToken(
@RequestParam("grant_type") String grantType, // "refresh_token"์ผ๋ก ๊ณ ์
@RequestParam("client_id") String clientId,
@RequestParam("refresh_token") String refreshToken,
@RequestParam("client_secret") String clientSecret
);
}
Service๋ก ํตํฉ
`Google`๊ณผ `Kakao`์ API ํธ์ถ ๋ก์ง์ ํ๋์ Service๋ก ํตํฉํ์ฌ, ๊ฐ ์์ ๋ก๊ทธ์ธ ์ ๊ณต์์ ๋ํ `์ฐ๊ฒฐ ํด์ `, `ํ ํฐ ๊ฐฑ์ `์ ์ฒ๋ฆฌํฉ๋๋ค.
@Slf4j
@RequiredArgsConstructor
@Service
public class SocialClientService {
...
// Google ํ ํฐ ๊ฐฑ์ ์์ฒญ
public TokenResponse reissueGoogleToken(String refreshToken) {
return googleClient.reissueToken(
GRANT_TYPE_REFRESH_TOKEN,
googleClientId,
refreshToken,
googleClientSecret
);
}
// Google ์ฐ๊ฒฐ ํด์ ์์ฒญ
public void unlinkGoogle(String accessToken) {
googleClient.unlink(accessToken);
log.info("Google Unlink");
}
// Kakao ํ ํฐ ๊ฐฑ์ ์์ฒญ
public TokenResponse reissueKakaoToken(String refreshToken) {
return kakaoAuthClient.reissueToken(
GRANT_TYPE_REFRESH_TOKEN,
kakaoClientId,
refreshToken,
kakaoClientSecret
);
}
// Kakao ์ฐ๊ฒฐ ํด์ ์์ฒญ
public void unlinkKakao(String accessToken) {
UnlinkResponse response = kakaoApiClient.unlink(accessToken);
log.info("Kakao Unlink ํ์๋ฒํธ : {}", response.getId());
}
}
OAuth2 ์ธ์ฆ ์ฒ๋ฆฌ ๋ฐฉ์ ์ปค์คํฐ๋ง์ด์ง
OAuth2AuthorizedClientService ์ปค์คํฐ๋ง์ด์ง
`OAuth2AuthorizedClientService`์ ๊ธฐ๋ณธ ๊ตฌํ์ฒด๋ `InMemoryOAuth2AuthorizedClientService`๋ก, ์ธ์ฆ ์๋ฒ์์ ๋ฐ๊ธ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋๋ฐ, ์ด๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ํ์ ๋ ๋ฉ๋ชจ๋ฆฌ ๋ฆฌ์์ค
- ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ํ์ ์ ์ ๋๋ค. ์ฌ์ฉ์ ์๊ฐ ์ฆ๊ฐํ๋ฉด, ๋ฉ๋ชจ๋ฆฌ ๋ถํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์๋ฒ ํ์ฅ์ฑ ๋ฌธ์
- ์๋ฒ๋ฅผ ํ์ฅํ ๊ฒฝ์ฐ, ๊ฐ ์๋ฒ๋ ๋ ๋ฆฝ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฐ๊ฒ ๋ฉ๋๋ค. ์ด๋ก ์ธํด ์๋ฒ ๊ฐ ์ธ์ฆ ์ ๋ณด์ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํ์ฌ ๋จ๊ณ์์ ์ด๋ฌํ ๋ฌธ์ ๋ค์ด ์ง์ ์ ์ธ ๊ณ ๋ ค ๋์์ ์๋์ง๋ง, ํฅํ ์์คํ ์ ํ์ฅ์ฑ๊ณผ `TTL(Time To Live)` ์ค์ ์ ํ์ฉํ ํจ์จ์ ์ธ ํ ํฐ ๊ด๋ฆฌ๋ฅผ ์ํด `Redis`๋ฅผ ํตํ ํ ํฐ ์ ์ฅ ๋ฐฉ์์ ์ ํํ์ต๋๋ค.
@Override
public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal) {
String loginId = principal.getName();
OAuth2RefreshToken refreshToken = authorizedClient.getRefreshToken();
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
// Refresh ํ ํฐ ์ ์ฅ
String key = RedisTokenService.OAUTH2_REFRESH_TOKEN_KEY_PREFIX + loginId;
redisTokenService.saveToken(
key,
refreshToken.getTokenValue(),
Date.from(
LocalDateTime.now()
.plusWeeks(2)
.atZone(ZoneId.systemDefault())
.toInstant()
)
);
// Access ํ ํฐ ์ ์ฅ
key = RedisTokenService.OAUTH2_ACCESS_TOKEN_KEY_PREFIX + loginId;
redisTokenService.saveToken(
key,
accessToken.getTokenValue(),
Date.from(accessToken.getExpiresAt())
);
}
๐ก Refresh ํ ํฐ ์ ํจ ๊ธฐ๊ฐ์ 2์ฃผ๋ก ์ค์ ํ ์ด์
์์ ๋ก๊ทธ์ธ ์ ๊ณต์(`Google`, `Kakao`)๊ฐ ์ ๊ณตํ๋ Refresh ํ ํฐ์ ์ ํจ ๊ธฐ๊ฐ์ ์ต์ 2๊ฐ์ ์ด์์ด์ง๋ง, ์ฌ๋ก๊ทธ์ธ ์ ์ ๊ณต์๊ฐ ์๋ก์ด Refresh ํ ํฐ์ ๋ค์ ๋ฐ๊ธํด ์ค๋๋ค. ์ด๋ฅผ ๊ณ ๋ คํด, ์ ํฌ ์๋ฒ์์ ๋ฐ๊ธํ๋ Refresh ํ ํฐ(`JWT`)๊ณผ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ค์ ํ๋ ๊ฒ์ด ์ ์ ํ๋ค๊ณ ํ๋จํ์ต๋๋ค. ๋ฐ๋ผ์ ์์ ๋ก๊ทธ์ธ ์ ๊ณต์์ Refresh ํ ํฐ ์ ํจ ๊ธฐ๊ฐ๋ ๋์ผํ๊ฒ 2์ฃผ๋ก ์ค์ ํ์์ต๋๋ค.
OAuth2AuthorizationRequestResolver ์ปค์คํฐ๋ง์ด์ง
`Google`์์๋ ๋ก๊ทธ์ธ์ ํตํด Refresh ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ผ๋ ค๋ฉด ์ถ๊ฐ์ ์ธ ํ๋ผ๋ฏธํฐ ์ค์ ์ด ํ์ํฉ๋๋ค. ๋ฌผ๋ก Refresh ํ ํฐ ์์ด๋ ์ฐ๊ฒฐ ํด์ ์์ฒญ์ ๊ฐ๋ฅํ์ง๋ง, Access ํ ํฐ์ ์ ํจ๊ธฐ๊ฐ์ด ์งง๊ธฐ ๋๋ฌธ์, ์ฐ๊ฒฐ ํด์ ์์ฒญ ์, ํ ํฐ์ด ๋ง๋ฃ๋์ด ์ฌ์ฉ์๊ฐ ๋ค์ ๋ก๊ทธ์ธํด์ผ ํ๋ ๋ถํธํจ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, `OAuth2AuthorizationRequestResolver`๋ฅผ ์ปค์ค๋ง์ด์งํ์ฌ ์์ ๋ก๊ทธ์ธ ์ ๊ณต์๊ฐ `Google`์ธ ๊ฒฝ์ฐ ํ์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ ์ ์๋๋ก ๊ตฌํํ์ต๋๋ค. ์ด๋ฅผ ํตํด Refresh ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ ์ธ์ฆ ์ํ๋ฅผ ์ง์์ ์ผ๋ก ์ ์งํ ์ ์๋๋ก ํ์ต๋๋ค.
ํ์ํ ํ๋ผ๋ฏธํฐ ์ค์
- access_type=offline
- prompt=consent
- ํญ์ ๋์ ํ๋ฉด์ ํ์ํ๊ณ , ๋ช ์์ ์ธ ๋์๋ฅผ ๊ตฌํด์ผ Refresh ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ ์ ์์ต๋๋ค.
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
return customizeAuthorizationRequest(defaultResolver.resolve(request));
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
return customizeAuthorizationRequest(defaultResolver.resolve(request, clientRegistrationId));
}
private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {
if (authorizationRequest == null) {
return null;
}
Object registrationId = authorizationRequest.getAttribute("registration_id");
// Google์ผ ๋๋ง Refresh ํ ํฐ์ ๋ฐ๊ธฐ ์ํด, ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
if (registrationId.equals("google")) {
return OAuth2AuthorizationRequest.from(authorizationRequest)
.additionalParameters(params -> {
params.put("prompt", "consent");
params.put("access_type", "offline");
})
.build();
}
// ๋ค๋ฅธ ์ ๊ณต์๋ ๊ทธ๋๋ก ๋ฐํ
return authorizationRequest;
}
ํ์ ํํด ์ฒ๋ฆฌ
@Transactional
public void deleteUserByLoginId(String loginId) {
String refreshKey = RedisTokenService.OAUTH2_REFRESH_TOKEN_KEY_PREFIX + loginId;
String accessKey = RedisTokenService.OAUTH2_ACCESS_TOKEN_KEY_PREFIX + loginId;
String accessToken = redisTokenService.getToken(accessKey);
String registrationId = loginId.split(PROVIDER_ID_DELIMITER)[0];
if (registrationId.equals(KAKAO)) {
// Access ํ ํฐ์ด null์ด๋ฉด Refresh ํ ํฐ์ ์ด์ฉํด ์ฌ๋ฐ๊ธ
if (accessToken == null) {
TokenResponse tokenResponse = socialClientService.reissueKakaoToken(redisTokenService.getToken(refreshKey));
// ํ์ ํํด๋ฅผ ์ํ ์ฌ๋ฐ๊ธ์ด๊ธฐ ๋๋ฌธ์, Redis์ ์ ์ฅํ์ง ์์
accessToken = tokenResponse.getAccess_token();
}
socialClientService.unlinkKakao(BEARER_PREFIX + accessToken);
}
if (registrationId.equals(GOOGLE)) {
if (accessToken == null) {
TokenResponse tokenResponse = socialClientService.reissueGoogleToken(redisTokenService.getToken(refreshKey));
accessToken = tokenResponse.getAccess_token();
}
socialClientService.unlinkGoogle(accessToken);
}
// Refresh ํ ํฐ์ ๋จ์์๊ธฐ ๋๋ฌธ์ ์ญ์
redisTokenService.deleteToken(refreshKey);
// ์ ์ ์ isDeleted๋ฅผ true๋ก ๋ณ๊ฒฝ
User user = userRepository.findByLoginId(loginId)
.orElseThrow(() -> new ApiException(USER_NOT_FOUND));
user.delete();
}
- ์์
๋ก๊ทธ์ธ ์ ๊ณต์๋ณ ํ ํฐ ์ฒ๋ฆฌ
- ์์ ๋ก๊ทธ์ธ ์ ๊ณต์(`Google`, `Kakao`)์ ๋ฐ๋ผ Redis์์ Access ํ ํฐ์ ๊ฐ์ ธ์ต๋๋ค
- Access ํ ํฐ์ด ๋ง๋ฃ๋์ด Redis์ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ, Refresh ํ ํฐ์ ์ฌ์ฉํ์ฌ ์๋ก์ด Access ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ต๋๋ค.
- ์์
๊ณ์ ์ฐ๊ฒฐ ํด์
- ๋ฐ๊ธ๋ฐ์ Access ํ ํฐ์ ์ฌ์ฉํด ์์ ๋ก๊ทธ์ธ ์ ๊ณต์์๊ฒ ๊ณ์ ์ฐ๊ฒฐ ํด์ ๋ฅผ ์์ฒญํฉ๋๋ค.
- ํ ํฐ ์ ๋ฆฌ
- Redis์ ๋จ์์๋ Refresh ํ ํฐ์ ์ญ์ ํฉ๋๋ค.
- ์ฌ์ฉ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํด๋น ์ฌ์ฉ์์ `isDeleted` ํ๋๋ฅผ `true`๋ก ๋ฐ๊พธ์ด, ์ญ์ ์ํ๋ก ๋ณ๊ฒฝํฉ๋๋ค.
ํ์ ํํด ํ, ๋ค์ ๊ฐ์
ํ์ ํํด ํ ๋ค์ ๋ก๊ทธ์ธํ ๊ฒฝ์ฐ, ๋์ผํ ์ ํ๋ฆฌ์ผ์ด์
๋ด์์ `๊ณ ์ ID`๋ ์ ์ง๋ฉ๋๋ค. ์ฆ, ๊ณ์ ์ฐ๊ฒฐ์ ํด์ ํ๊ณ ๋ค์ ์ฐ๊ฒฐํด๋ `๊ณ ์ ID`๋ ๋ฐ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ํ์ ํํด ํ ์ฌ ๋ก๊ทธ์ธ ์, ๊ธฐ์กด ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ฉฐ `nickname`๊ณผ `profileImage` ํ๋๋ฅผ ์
๋ฐ์ดํธํ๊ณ , `isDeleted` ์ํ๋ฅผ `false`๋ก ๋ณ๊ฒฝํ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ์์ต๋๋ค.
(ํ์ ํํด ์, ์ฌ์ฉ์๊ฐ ์์ฑํ๋ ๋ฆฌ๋ทฐ, ๋ถ๋งํฌ ๋ฑ๊ณผ ๊ฐ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ๊ณผ ๋ค์ ๊ฐ์
ํ ๊ฒฝ์ฐ์ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ถํ์ ์ถ๊ฐ๋ก ๋
ผ์ํ ์์ ์
๋๋ค.)
@Transactional
public OAuth2User processOAuth2User(OAuth2Response oAuth2Response) {
String uniqueProviderId = oAuth2Response.getProvider() + PROVIDER_ID_DELIMITER + oAuth2Response.getProviderId();
String nickname = oAuth2Response.getNickname();
String profileImage = oAuth2Response.getProfileImage();
if (!userRepository.existsByLoginId(uniqueProviderId)) {
userRepository.save(
new User(
uniqueProviderId,
null,
nickname,
profileImage,
null,
null
)
);
OAuth2UserDto oAuth2UserDto = new OAuth2UserDto(uniqueProviderId);
return new OAuth2UserImpl(oAuth2UserDto);
}
User user = userRepository.findByLoginId(uniqueProviderId)
.orElseThrow(() -> new ApiException(USER_NOT_FOUND));
if (user.isDeleted()) {
user.reactivate();
}
user.update(
null,
nickname,
profileImage
);
OAuth2UserDto oAuth2UserDto = new OAuth2UserDto(uniqueProviderId);
return new OAuth2UserImpl(oAuth2UserDto);
}
๊ฒฐ๊ณผ
ํ์ ํํด ์, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์์ ์ญ์ ๋ฟ๋ง ์๋๋ผ, ์์ ๋ก๊ทธ์ธ ์ ๊ณต์ ์ธก์์๋ ๊ณ์ ์ฐ๊ฒฐ์ ํด์ ํ์ฌ ๋ณด๋ค ์์ฑ๋ ์๋ ํ์ ํํด ๊ธฐ๋ฅ์ ๊ตฌํํ์ต๋๋ค.
- Redis๋ฅผ ํ์ฉํ์ฌ ์์ ๋ก๊ทธ์ธ ์ ๊ณต์๊ฐ ์ ๋ฌํด ์ฃผ๋ ํ ํฐ์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌ
- OpenFeign์ ํตํ REST API ์์ฒญ
- OAuth2 ์ธ์ฆ ๊ด๋ จ ์ธํฐํ์ด์ค ์ปค์คํ ๊ตฌํ
- ๊ณ ์ ID์ ์ํํธ ๋๋ฆฌํธ๋ฅผ ํ์ฉํ์ฌ ํ์ ํํด ํ ์ฌ๊ฐ์ ์, ์ฌ์ฉ์ ๋ฐ์ดํฐ ์ ์ง
๋ํ, ์์ ์ธ๊ธํ ๊ฒ์ฒ๋ผ, ํํด ์ ์ฌ์ฉ์์ ์ฐ๊ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐ ์ฌ๊ฐ์ ์์ ์ฒ๋ฆฌ์ ๋ํด์๋ ์ถ๊ฐ์ ์ผ๋ก ๋ ผ์ ํ ๊ตฌํํ ๊ณํ์ ๋๋ค.
์ฐธ๊ณ
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko
'ํ๋ก์ ํธ > NolGoat' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์นด์นด์ค ๋ก๊ทธ์ธ ๋์ ํญ๋ชฉ ๋ฌธ์ ํด๊ฒฐ (1) | 2024.12.11 |
---|---|
๋ณด์ ์ทจ์ฝ์ ํด๊ฒฐ์ ์ํ AWS S3 ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ณ๊ฒฝ (0) | 2024.12.07 |
ํจ์จ์ ์ธ ํ ํฐ ๊ด๋ฆฌ๋ฅผ ์ํ Redis ๋์ (1) | 2024.11.29 |
์ธ์ฆ ๋ณด์ ๊ฐํ (0) | 2024.11.29 |
์ธ์ฆ์ด ํ์ํ URL ๊ณตํต ๊ด๋ฆฌ (0) | 2024.11.27 |