{"id":24005259,"url":"https://github.com/delight-hk3/sns-login-refactoring","last_synced_at":"2026-05-04T21:31:54.539Z","repository":{"id":271214607,"uuid":"912736077","full_name":"delight-HK3/sns-login-Refactoring","owner":"delight-HK3","description":"testproject sns login part Refactoring","archived":false,"fork":false,"pushed_at":"2025-04-14T12:43:55.000Z","size":585,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-30T16:52:15.557Z","etag":null,"topics":["bootstrap","java17","oauth2","spring-boot","thymeleaf"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/delight-HK3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-06T09:38:33.000Z","updated_at":"2025-04-18T07:26:38.000Z","dependencies_parsed_at":"2025-01-07T12:03:08.529Z","dependency_job_id":"085c3ee9-0655-4e55-a928-f40898c1c326","html_url":"https://github.com/delight-HK3/sns-login-Refactoring","commit_stats":null,"previous_names":["delight-hk3/sns-login-refactoring"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/delight-HK3/sns-login-Refactoring","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delight-HK3%2Fsns-login-Refactoring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delight-HK3%2Fsns-login-Refactoring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delight-HK3%2Fsns-login-Refactoring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delight-HK3%2Fsns-login-Refactoring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/delight-HK3","download_url":"https://codeload.github.com/delight-HK3/sns-login-Refactoring/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delight-HK3%2Fsns-login-Refactoring/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32625946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootstrap","java17","oauth2","spring-boot","thymeleaf"],"created_at":"2025-01-08T02:36:06.033Z","updated_at":"2026-05-04T21:31:54.521Z","avatar_url":"https://github.com/delight-HK3.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sns login Refactoring\nOAuth2.0기술에대해 이론을 정리하던 중 예전에 개발한 OAuth2.0을 활용한 SNS로그인 코드를 보게 되었습니다. 기존코드는 **FeignClient**을 사용하여 엑세스 토큰 및 유저 정보를 불러오는 방식을 사용했습니다.\n하지만 기존의 코드를 분석해보니 다음과 같은 문제를 확인 할 수 있었습니다.\n\u003e SNSLogin Repository : https://github.com/delight-HK3/testproject.git\n\n```\n기술스택\n\nFramework : Spring boot 3.3.6\nLanguage : Java 17\nTool : Visual Studio Code\n```\n\n### 문제점\n\n#### 2025/02/06 발견\n1. FeginClient 대신 RestTemplate를 사용한 것은 좋았으나 확인해보니 deprecated될 뻔했던 기술인 것을 확인\n   - RestTemplate 대신에 좀더 고도화된 RestClient를 도입할 계획\n\n#### 2025/02/04 발견\n1. SNS별로 Authorization서버주소, Resource서버주소 모두 다르기 때문에 주소별로 FeginClient를 만들어야한다.\n   - 물론 기존의 FeginClient를 쓰면서 서버간 통신 코드가 간결해졌습니다, 만약 Authorization서버 및 Resource서버의 도메인이 같았으면 FeginClient를 계속 사용했을 것 입니다. 하지만 Authorization서버 및 Resource서버의 도메인이 모두 달랐고 결과적으로 서버요청 기능 파일이 늘어났습니다.\n\n2. 똑같은 기능에 똑같은 코드의 반복하기에 중복 코드가 늘어난다.\n   - accessToken과 Resource서버에서 유저정보를 가져오는 코드는 같은데 구현체마다 중복되는 코드가 생기게 되었습니다.\n\n3. 코드의 가독성 저하문제\n\n---\n\n### 문제해결\n\n#### 2025/04/05 (1번 문제해결)\n(FeginClient 대신 RestTemplate를 사용한 것은 좋았으나 확인해보니 deprecated될 뻔했던 기술인 것을 확인)\n- RestTemplate에서 RestClient로 변경했습니다.\n```java\n// RestTemplate 방식\nHttpHeaders headers = new HttpHeaders();\nheaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\nHttpEntity entity = new HttpEntity(params, headers);\n\nResponseEntity\u003cJsonNode\u003e responseNode = \n        restTemplate.exchange(accesstokenUrl, HttpMethod.POST, entity, JsonNode.class);\n\n// RestClient 방식\nResponseEntity\u003cJsonNode\u003e responseNode = restClient.post()\n                                .uri(accesstokenUrl)\n                                .contentType(MediaType.APPLICATION_FORM_URLENCODED)\n                                .body(params)\n                                .retrieve()\n                                .toEntity(JsonNode.class);\n\n```\n\n#### 2025/04/05 (추가 문제해결)\n기존에 controller에서 SNS별로 JsonNode 객체를 userResponse에 저장하는 로직을 작성했는데 가독성이 떨어지고 controller에서 처리하는 것 보다는 service로직에서 정리는 것이 좋다고 판단해 service에서 수정되도록 수정했습니다. 추가로 userResponse에 setter를 제거하고 빌더패턴으로 변경했습니다.\n\n```java\n// controller 방식\nswitch (userType) {\n    case GOOGLE: { // 구글 sns로그인 출력결과 처리\n        userresponse.setId(jsonResponse.get(\"id\").asText());\n        userresponse.setEmail(jsonResponse.get(\"email\").asText());\n        userresponse.setNickname(jsonResponse.get(\"name\").asText());\n        break;\n    } case KAKAO: { // 카카오 sns로그인 출력결과 처리\n        userresponse.setId(jsonResponse.get(\"id\").asText());\n        userresponse.setEmail(jsonResponse.get(\"kakao_account\").get(\"email\").asText());\n        userresponse.setNickname(jsonResponse.get(\"kakao_account\").get(\"profile\").get(\"nickname\").asText());\n        break;\n    } case NAVER: { // 네이버 sns로그인 출력결과 처리\n        userresponse.setId(jsonResponse.get(\"response\").get(\"id\").asText());\n        userresponse.setEmail(jsonResponse.get(\"response\").get(\"birthday\").asText());\n        userresponse.setNickname(jsonResponse.get(\"response\").get(\"nickname\").asText());\n        break;\n    } default: {\n        throw new RuntimeException(\"NONE SOCIAL TYPE\");\n    }\n}\n\n// service 방식 (구글 로그인)\n// 구글 로그인 jsonNode 정리\n@Override\npublic userResponse getResponse(JsonNode jsonNode) {\n        return userResponse.builder()\n                            .id(jsonNode.get(\"id\").asText())\n                            .email(jsonNode.get(\"email\").asText())\n                            .nickname(jsonNode.get(\"name\").asText())\n                            .build();\n}\n```\n\n\n#### 2025/02/04 (1번 문제해결)\n(SNS별로 Authorization서버주소, Resource서버주소 모두 다르기 때문에 주소별로 FeginClient를 만들어야한다.)\n- FeginClient 대신 RestTemplate객체, HttpEntity객체를 사용하여 서버와 통신하고 값을 ResponseEntity로 받는방법을 사용했습니다. 또한 JsonNode를 사용하면서 복잡한 구조의 Response를 저장할 수 있게 되었습니다.\n\n```java\n// FeginClient 방식\n@FeignClient(value = \"googleAuth\", url=\"https://oauth2.googleapis.com\", configuration = {FeignConfiguration.class})\npublic interface GoogleAuthApi {\n    @PostMapping(\"/token\")\n    ResponseEntity\u003cString\u003e getAccessToken(@RequestBody GoogleRequestAccessTokenDto requestDto);\n}\n\n// RestTemplate, HttpEntity, JsonNode 방식\n\n// Authorization 서버를 통해 accesstoken 발급\nprivate String getAccessToken(UserType userType, String authorizationCode){\n    MultiValueMap\u003cString,Object\u003e params = new LinkedMultiValueMap\u003c\u003e();\n    \n    String accesstokenUrl = environment.getProperty(\"spring.OAuth2.\"+userType+\".Authorization-url\");\n    \n    // 각 sns별 Authorization 서버주소\n    params.add(\"code\",authorizationCode);\n    params.add(\"client_id\", environment.getProperty(\"spring.OAuth2.\"+userType+\".client-id\"));\n    params.add(\"client_secret\",environment.getProperty(\"spring.OAuth2.\"+userType+\".client-secret\"));\n    params.add(\"redirect_uri\", environment.getProperty(\"spring.OAuth2.\"+userType+\".callback-url\"));\n    params.add(\"grant_type\", \"authorization_code\"); \n\n    HttpHeaders headers = new HttpHeaders();\n    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\n    HttpEntity entity = new HttpEntity(params, headers);\n\n    ResponseEntity\u003cJsonNode\u003e responseNode = \n        restTemplate.exchange(accesstokenUrl, HttpMethod.POST, entity, JsonNode.class);\n        \n    JsonNode accessTokenNode = responseNode.getBody();\n\n    return accessTokenNode.get(\"access_token\").asText();\n}\n```\n\n\u003cbr\u003e\n\n#### 2025/02/04 (2번 문제해결)\n똑같은 기능에 똑같은 코드의 반복하기에 중복 코드가 늘어난다.\n\n- 중복코드는 Authorization 서버 및 Resource 서버 요청 코드였기에 이 문제는 어떻게 보면 properties 설정을 @Value 으로 받아왔기에 유연하게 받는 것이 불가능했습니다. 그래서 Environment 객체를 활용해 properties 설정 파일값을 받아오는 방식으로 해결했습니다, userType을 변수로 받아 SNS별로 설정값이 다르게 입력되도록 변경했습니다. \n\n```java\n// @Value 어노테이션 방식\n@Value(\"${spring.OAuth2.Naver.client-id}\")\nprivate String NAVER_SNS_CLIENT_ID;\n\n@Value(\"${spring.OAuth2.Naver.client-secret}\")\nprivate String NAVER_SNS_CLIENT_SECRET;\n\n// Environment 방식\nenvironment.getProperty(\"spring.OAuth2.\"+userType+\".client-id\"));\nenvironment.getProperty(\"spring.OAuth2.\"+userType+\".client-secret\"));\n``` \n\n\u003cbr\u003e\n\n#### 2025/02/04 (3번 문제해결)\n- 코드 가독성문제는 기능별로 Authorization서버역할과 Resource서버의 역할을 확실히 구분지어 주석으로 작성했습니다.\n\n\u003cbr\u003e\n\n#### 2025/02/04 예상치 못한 성과\n원래는 SNS 로그인과 일반 로그인의 service를 공유하고 있었습니다. 그래서 일반 로그인과 SNS 로그인의 로직을 완전히 분리해 보니 프로그램의 확장성과 유연성이 상승하는 결과를 볼 수 있었습니다.\n\n---\n\n### 실행 시 주의사항\n1. application.properties 파일의 SNS 클라이언트 및 비밀키를 사용자가 발급받은 것으로 입력 해야합니다.\n2. 각 SNS별 callback 주소도 사용자가 설정한 것으로 입력해야합니다.\n\u003cbr\u003e\n\n### 리펙토링 작업과 관련된 블로그 게시글\nhttps://velog.io/@half-phycho/Refactoring-sns-로그인-리펙토링\n\u003cbr\u003e\n\n### 참고한 git Repository\nhttps://github.com/darren-gwon/springboot_oauth_example.git\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelight-hk3%2Fsns-login-refactoring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdelight-hk3%2Fsns-login-refactoring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelight-hk3%2Fsns-login-refactoring/lists"}