티스토리 뷰
개인 프로젝트에 OAuth2를 적용해봤다
Spring Security를 이용한 로그인, 회원가입 과정을 대체하기 위해서는 아니고 학습 목적이다
학습 목적이라 해보고 싶은 것 다 하려고 google, facebook, github, naver, kakao 다 연결시켰다
SpringBoot 프로젝트에 OAuth2 적용하는 과정은 자세히 설명해준 글을 첨부한다
- 1편
- 2편
위 블로그 글을 참고하여 내 프로젝트에 필요한 부분은 도입하고 필요하지 않거나 리팩토링이 가능한 부분은 고쳐서 사용했다
if 문으로 층층이 검사하는 코드에서 switch문을 사용하도록 변경했다
이 조차도 다형성을 이용하는 객체지향적 코드로 변경할 수 있을 것 같은데 이 외에도 할 게 많아서 조금 미뤄두기로 했다
- 블로그 하단에 수정버전이 있다
오른쪽 코드에서 method 옆에 Complexity is 5 Everything is cool! 이라고 적힌 것은 인텔리제이의 플러그인이다
CodeMetrics라는 플러그인으로 코드의 복잡도를 계산해서 알려준다
특히 if문, 중첩 if문에 점수가 크게 배정되므로 if문 덩어리에 때려 박는 코드를 지양할 수 있게 해 준다
if문을 싫어하는 것을 보면 복잡도의 기준은 아무래도 클린 코드의 영향을 받은 것 같다
요즘 읽고 있는 클린 코드에서도 if문, switch문을 객체지향적인 코드로 대체하라고 강조하고 있다
한번 작성하고 다시는 돌아보지 않을 코드라면 돌아가기만 하면 되겠지만
자신의 작품이기도 하고 나는 꾸준히 리팩토링을 해 볼 생각이라 가독성을 좋게 만들려 노력하고 있다
아래 사진은 OAuth2를 적용 후 테스트를 돌리다 만난 에러다 로그 트레이스는 상당히 길지만 핵심적인 부분만 올렸다
아래 코드에서 clientId가 null이 나오기 때문에 터진 에러이고
내가 작성한 application.yml을 다시 살펴보고 application-oauth2.yml도 살펴봤는데 이상은 없었다
또한 SpringBootApplication을 돌릴 때 에러가 터지지 않는 것을 생각해보면 설정 파일에는 문제가 없었고
다시 한번 문제를 살폈는데 문제는 test 폴더에 있었다
private ClientRegistration getRegistration(String client) {
String clientId = env.getProperty(CLIENT_PROPERTY_KEY + client + ".client-id");
String clientSecret = env.getProperty(CLIENT_PROPERTY_KEY + client + ".client-secret");
switch (client) {
case "kakao":
return CustomOAuth2Provider.KAKAO.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
case "naver":
return CustomOAuth2Provider.NAVER.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
case "google":
return CommonOAuth2Provider.GOOGLE.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
case "github":
return CommonOAuth2Provider.GITHUB.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
case "facebook":
return CommonOAuth2Provider.FACEBOOK.getBuilder(client).clientId(clientId).clientSecret(clientSecret).build();
default:
return null;
}
}
나는 test를 애플리케이션과 독립적인 환경에서 돌리고 싶었기 때문에 test를 위한 application.yml을 따로 작성해두었고
폴더 구조는 좌측과 같고 application.yml의 대략적인 모습은 우측과 같다
@SpringBootTest는 test 폴더 안에 application.yml이 존재한다면 메인 application.yml보다 우선권을 가지고 읽어온다
테스트용 application.yml에 oauth2 설정에 해당하는 내용이 없기 때문에 에러가 터질 수밖에 없는 구조다
테스트 폴더의 application.yml은 github에 올려둔 상태고 나머지 *. yml 파일들은. gitignore에 등록해두었기 때문에
application 폴더에 가지고 있던 application-oauth2.yml을 복붙 하는 걸로 문제 해결되었다
OAuth2 적용을 설명해주는 블로그가 많기에 자료는 많고 나와 같은 문제를 만나는 분이 계시다면 해결에 참고하시라 올려본다
2022.01.08 수정 버전
위쪽부터 살펴보자면 가독성을 위해 메서드 참조를 사용하지 않았는데 람다 사용에 조금 익숙해져서 리팩토링 때 수정했고
이 부분을 수정하는데 객체지향적인 사고 같은 거창한 건 필요 없고 Enum 의 valueOf 메서드만 알면 됐던 문제다
Enum.valueOf("문자열") 의 형태로 사용하며 문자열이 유효하다면 문자열에 맞는 타입으로 변환된다
예를 들어 google 로 넘어왔다면 우선 대문자로 변환 후 CustomOAuth2Provider.GOOGLE 로 변환되는 것이다
"google".toUpperCase() -> "GOOGLE"
CustomOAuth2Provider.valueOf("GOOGLE") -> CustomOAuth2Provider.GOOGLE
위 코드를 리팩토링하던 도중 switch문을 사용하는 비슷한 흐름의 코드 또한 리팩토링했다
리팩토링 이전 버전
public static OAuth2Attributes of(String registrationId, String userNameAttributeName, Map<String, Object> attributes) {
switch (registrationId) {
case "kakao":
return ofKakao(userNameAttributeName, attributes);
case "naver":
return ofNaver(userNameAttributeName, attributes);
case "google":
return ofGoogle(userNameAttributeName, attributes);
case "github":
return ofGithub(userNameAttributeName, attributes);
case "facebook":
return ofFacebook(userNameAttributeName, attributes);
default:
return null;
}
}
리팩토링 이후 버전
이건 솔직히 이러한 형태가 낫다고 할 수 있을지 모르겠다
switch 문 대신 Map 자료구조를 통해 BiFunction을 꺼내고 apply로 적용시키도록 하여 코드는 짧아졌으나
코드를 작성한 내가 아닌 남이 봤을 때 직관적이고, 쉽게 이해할 수 있는 것은 switch 문 일것 같다
근데 사실 저 정도의 코드는 어려운 축에도 끼지 못 할거 같고 내가 봤을 때 깔끔하기 때문에 리팩토링이 저렇게 완성됐다
'Spring > Spring Security' 카테고리의 다른 글
[JWT] 회원 아이디 & 비밀번호 찾기 feat. coolsms-api (0) | 2021.11.06 |
---|---|
[JWT] jwt 로그아웃 구현 (0) | 2021.11.04 |
[OAuth2] /oauth2/authorization/github 404 (0) | 2021.10.23 |
[OAuth2] SecurityConfig, OAuth2Config 설정 리팩토링 (0) | 2021.10.23 |
[PreAuthorize] Annotation Custom Check Method, 커스텀 체크 (0) | 2021.10.11 |