0. 구글 개발자 설정
[SpringSecurity] 구글 로그인 연동하기 1 - 구글 서비스 등록
1. GoogleOAuthRequest
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class GoogleOAuthRequest {
private String redirectUri;
private String clientId;
private String clientSecret;
private String code;
private String responseType;
private String scope;
private String accessType;
private String grantType;
private String state;
private String includeGrantedScopes;
private String loginHint;
private String prompt;
}
2. GoogleOAuthResponse
import lombok.Data;
@Data
public class GoogleOAuthResponse {
private String accessToken;
private String expiresIn;
private String refreshToken;
private String scope;
private String tokenType;
private String idToken;
}
3. GoolgeVO
import lombok.Data;
import lombok.ToString;
/**
*
iss=https://accounts.google.com,
azp=65465-scmetkg9rf7g0anodi1g4rfp434f81c7rfu.apps.googleusercontent.com,
aud=2383873471124-scmetkg9rf7g0ano5di431g24rf32pf81c7rfu.apps.googleusercontent.com,
sub=1012804324239237390221439,
email=honggidong@gmail.com,
email_verified=true,
at_hash=Dv79dcE0q6Ydsadn2uxR5FJpHw,
name=홍길동,
picture=https://lh3.googleusercontent.com/a/AGNmyxZ-H_5vaMlSUoYZpdXFd134nFl63lJ-gCsJ7icmj3sA=s96-c,
given_name=길동,
family_name=홍,
locale=ko,
iat=16818033226,
exp=16813806826,
alg=RS4256,
kid=9697180428796829a92372e7949d1a9fff14231cd61b1e3,
typ=JWT
*
*/
@Data
@ToString
public class GoolgeVO {
private String id;
private String email;
private String name;
private String picture ;
private String given_name;
private String family_name;
private String oauth;
}
4.GoogleOAuthURL
public class GoogleOAuthURL {
final static String GOOGLE_AUTH_BASE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
final static String GOOGLE_TOKEN_BASE_URL = "https://oauth2.googleapis.com/token";
final static String GOOGLE_REVOKE_TOKEN_BASE_URL = "https://oauth2.googleapis.com/revoke";
///login/oauth2/code/google
final static String REDIRECT_URI = "http://localhost:8080/login/google/auth";
final static String CLIENT_ID = "클라이언트 아이디";
final static String CLIENT_SECRET = "클라이언트 시크릿";
public static String url(){
StringBuffer sb=new StringBuffer();
sb.append(GOOGLE_AUTH_BASE_URL);
sb.append("?client_id=");
sb.append(CLIENT_ID);
sb.append("&redirect_uri=");
sb.append(REDIRECT_URI);
sb.append("&response_type=code");
sb.append("&scope=email profile openid https://www.googleapis.com/auth/drive.file");
sb.append("&access_type=offline");
return sb.toString();
}
}
5.GoogleOAuthController
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.korea.webtoon.dao.MemberDAO;
@Controller
@RequestMapping("/login/google/")
public class GoogleOAuthController {
@Autowired
private MemberDAO memberDao;
/** 로그인페이지 로그인 첫 화면 요청 메소드 */
@RequestMapping(value = "login.do", method = { RequestMethod.GET, RequestMethod.POST })
public String join( Model model) {
model.addAttribute("urlGoogle",GoogleOAuthURL.url());
return "oauth/google/login";
}
/**
* Authentication Code를 전달 받는 엔드포인트
**/
@GetMapping("auth")
public String googleAuth(Model model, @RequestParam(value = "code") String authCode)
throws JsonProcessingException {
// HTTP Request를 위한 RestTemplate
RestTemplate restTemplate = new RestTemplate();
// Google OAuth Access Token 요청을 위한 파라미터 세팅
GoogleOAuthRequest googleOAuthRequestParam = GoogleOAuthRequest.builder().clientId(GoogleOAuthURL.CLIENT_ID)
.clientSecret(GoogleOAuthURL.CLIENT_SECRET).code(authCode).redirectUri("http://localhost:8080/login/google/auth")
.grantType("authorization_code").build();
// JSON 파싱을 위한 기본값 세팅
// 요청시 파라미터는 스네이크 케이스로 세팅되므로 Object mapper에 미리 설정해준다.
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
mapper.setSerializationInclusion(Include.NON_NULL);
// AccessToken 발급 요청
ResponseEntity<String> resultEntity = restTemplate.postForEntity(GoogleOAuthURL.GOOGLE_TOKEN_BASE_URL, googleOAuthRequestParam,
String.class);
// Token Request
GoogleOAuthResponse result = mapper.readValue(resultEntity.getBody(), new TypeReference<GoogleOAuthResponse>() {});
// ID Token만 추출 (사용자의 정보는 jwt로 인코딩 되어있다)
String jwtToken = result.getIdToken();
String requestUrl = UriComponentsBuilder.fromHttpUrl("https://oauth2.googleapis.com/tokeninfo")
.queryParam("id_token", jwtToken).encode().toUriString();
String resultJson = restTemplate.getForObject(requestUrl, String.class);
Map<String, String> userInfo = mapper.readValue(resultJson, new TypeReference<Map<String, String>>() {});
System.out.println("userInfo 정보 " +userInfo.toString());
GoolgeVO googleVO=new GoolgeVO();
googleVO.setId("google_"+userInfo.get("kid"));
googleVO.setEmail(userInfo.get("email"));
googleVO.setName(userInfo.get("name"));
googleVO.setPicture(userInfo.get("picture"));
googleVO.setOauth("google");
//DB 에 저장 및 업데이트 처리
memberDao.saveOauthGoole(googleVO);
model.addAllAttributes(userInfo);
model.addAttribute("token", result.getAccessToken());
System.out.println(userInfo);
return "oauth/google/loginSuccess";
}
/**
* 토큰 무효화
**/
@GetMapping("revoke/token")
@ResponseBody
public Map<String, String> revokeToken(@RequestParam(value = "token") String token) throws JsonProcessingException {
Map<String, String> result = new HashMap<>();
RestTemplate restTemplate = new RestTemplate();
final String requestUrl = UriComponentsBuilder.fromHttpUrl(GoogleOAuthURL.GOOGLE_REVOKE_TOKEN_BASE_URL)
.queryParam("token", token).encode().toUriString();
System.out.println("TOKEN ? " + token);
String resultJson = restTemplate.postForObject(requestUrl, null, String.class);
result.put("result", "success");
result.put("resultJson", resultJson);
return result;
}
}
6.login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>google OAuth</title>
<style type="text/css">
#container{width:500px}
.sns_join a.google{border-color:#eb6155}
.sns_join a{display:block;margin-top:10px;width:100%;height:50px;border:1px solid #000;font-size:15px;line-height:50px;text-align:center;background:#fff}
.sns_join a.google>.icon{background:url(https://cdn.jsdelivr.net/gh/braverokmc79/ouath2-img@v1.0.0/images/icon_google.png) no-repeat 0 0;background-size:18px auto}
.sns_join a>.icon{display:inline-block;margin:0 auto;padding-left:29px;width:188px;color:#666;font-size:15px;letter-spacing:-1px;line-height:20px;text-align:left}
</style>
</head>
<body>
<div id="container">
<div class="sns_join">
<a class="google" href="${urlGoogle}" id="googleLoginBtn"> <span class="icon">구글 로그인</span>
</a>
</div>
</div>
</body>
<script>
const onClickGoogleLogin = (e) => {
window.location.replace('${src}')
}
const googleLoginBtn = document.getElementById("googleLoginBtn");
googleLoginBtn.addEventListener("click", onClickGoogleLogin)
</script>
</html>
7.loginSuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Google Login 완료</h1>
<div>${token}</div>
<div>${email}</div>
<div>
<img src="${picture}"></img>
</div>
<div>
<a href="/">홈</a>
</div>
</body>
</html>
db 저장 참조
<insert id="saveOauthGoole">
MERGE INTO WEBTOON_USER
USING DUAL ON (EMAIL = #{email} )
WHEN MATCHED THEN
UPDATE SET OAUTH = #{oauth}
WHEN NOT MATCHED THEN
INSERT (USER_IDX, NAME, ID, EMAIL, OAUTH)
VALUES( seq_user_idx.nextVal,
#{name},
#{id},
#{email},
#{oauth}
)
</insert>

















댓글 ( 4)
댓글 남기기