일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 스프링부트
- 국비지원
- 데이터베이스
- 자바개발자
- 리액트
- 미라클모닝
- React
- 코드업
- 프로그래밍
- 알고리즘
- 자바알고리즘
- 프로세스
- 혼공컴운
- 프로그래머스
- 소셜로그인구현
- 자바스크립트
- 개발자일기
- 백엔드개발자
- db
- SpringBoot
- 국비지원코딩
- 자바의정석
- Codeup
- 개발자
- 자바
- 백엔드
- Java
- 운영체제
- 코딩
- 프로그래머
- Today
- Total
초코딩(chocoding)
[Project - Spring Boot] 소셜 로그인/API - 구글 : 기본 초기 세팅 / 로그인 정보 db에 담기 / 1개의 service로 소셜 로그인 구현 / 로그아웃 구현 / 411 에러 해결 / 본문
[Project - Spring Boot] 소셜 로그인/API - 구글 : 기본 초기 세팅 / 로그인 정보 db에 담기 / 1개의 service로 소셜 로그인 구현 / 로그아웃 구현 / 411 에러 해결 /
sweetychocoding 2024. 1. 26. 12:36기본 초기 세팅은 아래 블로그를 참고하였다.
https://dev-coco.tistory.com/128
Spring Boot 게시판 OAuth 2.0 구글 로그인 구현
Spring Boot에 Spring Security와 OAuth2.0을 사용해 소셜 로그인을 구현해보도록 하자. 1. 구글 OAuth 서비스 등록 필자는 이미 만들어놓은 프로젝트가 있어 예시 프로젝트를 하나 생성해보도록 하겠다. 1-1.
dev-coco.tistory.com
.
.
.
지난번 게시물에서 controller를 하나로 합친다고 했는데..
일단 service를 합쳐보았다.
gate라는 변수를 하나 더 두어서, 어느 소셜을 통하여 로그인을 시도했는지 구분하였다.
들어온 경로를 기준으로 if문을 사용하여 코드를 짰고,
home.jsp에는 어떤 고객이 어떤 경로로 로그인 했는지 tag library를 이용하여 구현하였다.
또한 service 코드를 짜면서 411 에러가 떴는데
어떤 문제인지 구글링하다가
결국 chat gpt를 이용하였다 (지피티 최고...!!)
Feign Client Length Required 411 - 구글 소셜 로그인
구글 소셜 로그인 기능을 구현하는 과정 중, 구글에서 받은 인가코드를 이용하여 구글 API 서버에서 액세스 토큰을 얻어와야 하는 과정이 있다. 여기서 구글 API 서버에 토큰을 요청하는 것을 Feign
velog.io
"411 Length Required" 오류는 일반적으로 서버가 요청에 콘텐츠 길이를 기대하지만 해당 헤더가 포함되지 않았거나 0으로 설정되어 있을 때 발생합니다. 콘텐츠 길이를 0으로 설정하려면 서버가 빈 본문을 허용하는지 확인하는 것이 중요합니다.
해결 방법은 다음과 같습니다:
서버가 빈 요청 본문을 허용하는지 확인:
요청을 보내는 서버가 특정 엔드포인트에 대해 빈 본문을 허용하는지 확인하십시오. POST 요청에 대해 콘텐츠 길이가 0이어도 되도록 서버가 구성되어 있는지 확인하세요.
더미 본문을 보내보기:
몇몇 서버는 본문이 비어있더라도 콘텐츠 길이가 0이 아니어야 하는 경우가 있습니다.
.... 그렇다... !
하핫
.
.
.
LoginService (service를 합치면서 파일 이름 변경함)
package com.cm.personalProject.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Optional;
import org.springframework.stereotype.Service;
import com.cm.personalProject.domain.OauthId;
import com.cm.personalProject.entity.User;
import com.cm.personalProject.repository.UserRepository;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Service
@RequiredArgsConstructor
@Log4j2
public class LoginService {
private final UserRepository repository;
// getAccessToken
public String getAccessToken(String code, String gate) {
try {
String redirectURI = "";
String apiURL = "";
String access_token = "";
// String refresh_token = "";
System.out.println("apiURL=" + apiURL);
System.out.println("$$$$ code =>" + code);
if ("naver".equals(gate)) {
redirectURI = URLEncoder.encode("http://localhost:8080/social/nlogin", "UTF-8");
apiURL = "https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&";
apiURL += "client_id=" + "****1lTRrhBHowHEvL4f";
apiURL += "&client_secret=" + "****6CNy4Z";
apiURL += "&redirect_uri=" + "http://localhost:8080/social/nlogin";
apiURL += "&code=" + code;
apiURL += "&state=" + 1234;
} else if ("kakao".equals(gate)) {
redirectURI = URLEncoder.encode("http://localhost:8080/social/klogin", "UTF-8");
apiURL = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&";
apiURL += "&client_id=****0b218caf1b7c5c6faed3222c37d3";
apiURL += "&redirect_uri=http://localhost:8080/social/klogin";
apiURL += "&code=" + code;
apiURL += "&client_secret=****Gb1FU2Xa3QcDKodnB1zTzEQLzGn5";
} else if ("google".equals(gate)) {
redirectURI = URLEncoder.encode("http://localhost:8080/social/glogin", "UTF-8");
apiURL = "https://oauth2.googleapis.com/token?grant_type=authorization_code&";
apiURL += "&client_id=****95726733-k5cn43gdkr8oaus87c1avq98ro4roaoc.apps.googleusercontent.com";
apiURL += "&redirect_uri=http://localhost:8080/social/glogin";
apiURL += "&code=" + code;
apiURL += "&client_secret=****PX-463AWl7vax0Xw-eoHLEyt7X_F30k";
}
URL url = new URL(apiURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Length", "1");
con.setDoOutput(true);
OutputStream outputStream = con.getOutputStream();
outputStream.write(" ".getBytes());
outputStream.flush();
outputStream.close();
int responseCode = con.getResponseCode();
BufferedReader br;
System.out.print("responseCode=" + responseCode);
if (responseCode == 200) { // 정상 호출
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
} else { // 에러 발생
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
return null;
}
String inputLine;
StringBuffer res = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
res.append(inputLine);
}
if (responseCode == 200) {
System.out.println(res.toString());
}
String result = res.toString(); // 변경: 읽은 내용을 String으로 변환
System.out.println("response body : " + result);
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);
br.close();
return element.getAsJsonObject().get("access_token").getAsString();
} catch (Exception e) {
System.out.println(e);
return null;
}
}
// getUserInfo
public User getUserInfo(String accessToken, String gate) throws IOException {
String apiURL = "";
if ("naver".equals(gate)) {
apiURL = "https://openapi.naver.com/v1/nid/me";
} else if ("kakao".equals(gate)) {
apiURL = "https://kapi.kakao.com/v2/user/me";
} else if ("google".equals(gate)) {
apiURL = "https://www.googleapis.com/oauth2/v3/userinfo";
}
String headerStr = "Bearer " + accessToken; // Bearer 다음에 공백 추가
String result = requestToServer(apiURL, headerStr);
System.out.println("사용자 정보 " + result);
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);
String token_id = "";
String nickname = "";
String email = "";
// JsonObject response = element.getAsJsonObject().get(JsonObject);
if ("naver".equals(gate)) {
token_id = element.getAsJsonObject().get("response").getAsJsonObject().get("id").getAsString();
nickname = element.getAsJsonObject().get("response").getAsJsonObject().get("name").getAsString();
email = element.getAsJsonObject().get("response").getAsJsonObject().get("email").getAsString();
} else if ("kakao".equals(gate)) {
nickname = element.getAsJsonObject().get("properties").getAsJsonObject().get("nickname").getAsString();
email = element.getAsJsonObject().get("kakao_account").getAsJsonObject().get("email").getAsString();
token_id = element.getAsJsonObject().get("id").getAsString();
} else if ("google".equals(gate)) {
nickname = element.getAsJsonObject().get("name").getAsString();
email = element.getAsJsonObject().get("email").getAsString();
token_id = element.getAsJsonObject().get("sub").getAsString();
}
Optional<User> opt_user = repository.findById(new OauthId(gate, token_id));
System.out.println("--------opt_user : " + opt_user);
User user = new User();
if (opt_user.isPresent()) {
return opt_user.orElse(null);
} else {
user.setUseremail(email);
user.setUsername(nickname);
user.setOauthtype(gate);
user.setOauthtoken(token_id);
repository.save(user);
return user;
}
}
private String requestToServer(String apiURL, String headerStr) throws IOException {
URL url = new URL(apiURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
System.out.println("header Str: " + headerStr);
if (headerStr != null && !headerStr.equals("")) {
con.setRequestProperty("Authorization", headerStr);
}
int responseCode = con.getResponseCode();
BufferedReader br;
System.out.println("responseCode=" + responseCode);
if (responseCode == 200) { // 정상 호출
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
} else { // 에러 발생
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
String inputLine;
StringBuffer res = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
res.append(inputLine);
}
br.close();
if (responseCode == 200) {
return res.toString();
} else {
return null;
}
}
}
LoginController
package com.cm.personalProject.controller;
import java.io.IOException;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.cm.personalProject.entity.User;
import com.cm.personalProject.service.LoginService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Log4j2
@AllArgsConstructor
@RequestMapping(value = "/social")
@Controller
public class LoginController {
private LoginService loginService;
@GetMapping("/loginPage")
public void getLoginPage() {
}
@GetMapping("/klogin")
public String klogin(@RequestParam("code") String code, Model model, HttpSession session) {
System.out.println(code);
String access_token = loginService.getAccessToken(code, "kakao");
System.out.println("controller access_token : " + access_token);
try {
User userInfo = loginService.getUserInfo(access_token, "kakao");
System.out.println("*****************" + userInfo);
if (userInfo != null) {
session.setAttribute("loginUser", userInfo);
return "redirect:/home";
} else {
return "redirect:/social/loginPage";
}
} catch (Exception e) {
return "redirect:/social/loginPage";
}
} // klogin
@GetMapping("/nlogin")
public String nlogin(@RequestParam("code") String code, Model model, HttpSession session) {
System.out.println(code);
String access_token = loginService.getAccessToken(code, "naver");
try {
User userInfo = loginService.getUserInfo(access_token, "naver");
System.out.println("*****************" + userInfo);
if (userInfo != null) {
session.setAttribute("loginUser", userInfo);
return "redirect:/home";
} else {
return "redirect:/social/loginPage";
}
} catch (Exception e) {
return "redirect:/social/loginPage";
}
} //nlogin
@GetMapping("/glogin")
public String glogin(@RequestParam("code") String code, Model model, HttpSession session) {
System.out.println(code);
String access_token = loginService.getAccessToken(code, "google");
try {
User userInfo = loginService.getUserInfo(access_token, "google");
System.out.println("*****************" + userInfo);
if (userInfo != null) {
session.setAttribute("loginUser", userInfo);
return "redirect:/home";
} else {
return "redirect:/social/loginPage";
}
} catch (Exception e) {
return "redirect:/social/loginPage";
}
} //glogin
@GetMapping(value = "/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/home";
} //logout
}
loginPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/resources/css/login.css">
<title>social Login</title>
</head>
<body>
<div id="wrap">
<h2>소셜 로그인하기</h2>
<a href="https://kauth.kakao.com/oauth/authorize?client_id=****0b218caf1b7c5c6faed3222c37d3&redirect_uri=http://localhost:8080/social/klogin&response_type=code">
<img src="/resources/images/kakao_login_medium_wide.png" alt="kakaoLogin IMG" />
</a>
<br />
<a href="https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=****1lTRrhBHowHEvL4f&redirect_uri=http://localhost:8080/social/nlogin">
<img src="/resources/images/naver_login_logo.png" alt="naverLogin IMG" />
</a>
<br />
<a href="https://accounts.google.com/o/oauth2/auth?client_id=****95726733-k5cn43gdkr8oaus87c1avq98ro4roaoc.apps.googleusercontent.com&redirect_uri=http://localhost:8080/social/glogin&response_type=code&scope=email%20profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20openid&authuser=0&prompt=consent">
<img src="/resources/images/google_login_logo.png" alt="googleLogin IMG" />
</a>
</div>
</body>
</html>
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/resources/css/home.css">
<title>Insert title here</title>
</head>
<body>
<div id="wrap">
<c:choose>
<c:when test="${not empty sessionScope.loginUser}">
<h2>
${sessionScope.loginUser.username}님, 안녕하세요!
${sessionScope.loginUser.oauthtype}로 로그인하셨습니다.
</h2>
</c:when>
<c:otherwise>
<h2>로그인 후 이용해주세요. 😊</h2>
</c:otherwise>
</c:choose>
<div>
<img src="/resources/images/helloworld.png" alt="welcome">
</div>
<c:if test="${not empty sessionScope.loginUser}">
<a href="social/logout">로그아웃</a>
<a>게시판가기</a>
</c:if>
<c:if test="${empty sessionScope.loginUser}">
<a href="social/loginPage">로그인</a>
</c:if>
</div>
</body>
</html>
.
.
.
이로써... 카카오, 네이버, 구글 로그인 구현이 완료되었다
...으하하
개인 프로젝트이긴 하지만 스터디 그룹 팀원들의 도움을 많이 받았던 것 같다. (모두 모두 감사함당 ㅎ)
이제 주말동안 aws를 좀 알아보고...
다음주부터 바로 배포를 ... 해봐야 될 것 같다.
솔직히 말만 들었지 어떤 식으로 하는 지 1도 몰라서
공부가 많이 필요할 것 같다.
파이팅
...!!!!
리드미도 ... 해야지요...