스프링

 

 

카카오, 구글은 자바스크립트 로그인

 

SNS api 설정 및 참조

https://tyrannocoding.tistory.com/51

 

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.security.SecureRandom" %>
<%@ page import="java.math.BigInteger" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ include file="../common/header.jsp" %>


  <%
    // 네이버 로그인
    String clientId = "iDRiqlC1V1cqQU1U9LatV";//애플리케이션 클라이언트 아이디값";
    String redirectURI = URLEncoder.encode("http://localhost:8000/sns/naverCallback", "UTF-8");
    SecureRandom random = new SecureRandom();
    String state = new BigInteger(130, random).toString();
    String apiURL = "https://nid.naver.com/oauth2.0/authorize?response_type=code";
    apiURL += "&client_id=" + clientId;
    apiURL += "&redirect_uri=" + redirectURI;
    apiURL += "&state=" + state;
    session.setAttribute("state", state);
    //END 네이버 로그인
 %>
 <link rel="stylesheet" href="/css/loginStyle.css">
 <!-- 카카오 스크립트 -->
<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
 

 
<div class="login__wrapper" style="margin-top: 115px; height: 734px;">
    <div class="container">
        <div class="panel-body">
            <div class="mb-3">
                <label for="username">아이디(Email)</label>
                <div class="input-group">
                    <input type="text" class="form-control" id="username" placeholder="" name="user-id" required="required">
                        <div class="invalid-feedback" style="width: 100%;">Your username is required.</div>
                    </div>
                </div>

                <div class="mb-3">
                    <label for="username">비밀번호</label>
                    <div class="input-group">
                        <input type="password" class="form-control" id="pw" placeholder="" name="user-id" required="required">
                            <div class="invalid-feedback" style="width: 100%;">Your username is required.</div>
                        </div>
                    </div>
                </div>

                    <hr/>
                        <button id="login-btn" class="btn btn-primary btn-lg" style="width: 100%">로그인</button>
                    <hr/>

                    <div class="sign__container" style="left: -35px;position: relative;">
                        
                        <div class="other_id_join">
		                    <a class="naver" href="<%=apiURL%>" ><span class="sns_icon">네이버로 로그인</span></a>		                    
		                    <a class="kakao"  href="#" onclick="kakaoLogin();"><span class="sns_icon">카카오톡으로 로그인</span></a>
		                    <a class="google"  id="GgCustomLogin"  href="javascript:void(0);" ><span class="sns_icon">구글로 로그인</span></a>		                   
     				   </div>
                        
                        
                        <div class="sign__box" style="margin-top:20px; width: 490px ">
                            <span>아직 회원이 아니신가요?</span>
                            <a href="/user/join">회원가입</a>
                        </div>

 
 
                    </div>
        </div>
    </div>
<script src="/js/login.js"></script>


<script>
let naverError='${naverError}';
if(naverError!=""){
	alert(naverError);
}

Kakao.init('34ddf13d2cd34ca551657751f26ba8cc8'); //발급받은 키 중 javascript키를 사용해준다.
console.log(Kakao.isInitialized()); // sdk초기화여부판단
//카카오로그인
function kakaoLogin() {
    Kakao.Auth.login({
      success: function (response) {
        Kakao.API.request({
          url: '/v2/user/me',
          success: function (response) {
        	  console.dir(response);
        	  console.log(response.kakao_account.email);
        	  snsLoginProcess("kakao", response.id  ,response.kakao_account.email,response.kakao_account.profile.nickname);
        	
          },
          fail: function (error) {
            console.log(error)
          },
        })
      },
      fail: function (error) {
        console.log(error)
      },
    });
    
    return false;
}

function snsLoginProcess(type,id,email,nickname){
	console.log(type, id, email , nickname);
	
	$.ajax({
		url:"/sns/snsLoginProcess",	
		type:"post",
		data:{
			'snsType':type,
			'snsId':id,
			'email':email,
			'nickname' :nickname
		},
		success:function(resultMap){
			//console.log("ok");
			console.log(resultMap);
			
			if(resultMap.status=="success"){
				location.href="/";
			}else if(resultMap.status=="NoSuchElementException"){
				alert("등록되지 않은 회원입니다.");
			}else if(resultMap.status=="error"){
				alert("선택 제공 항목 카카오계정(이메일)을 선택해 주세요.");
			}
		},
		error:function(result){
			console.log(result);
			alert("카카오 로그인 오류");
		}
		
	});
	
	kakaoLogout();
}

//카카오로그아웃  
function kakaoLogout() {
    if (Kakao.Auth.getAccessToken()) {
      Kakao.API.request({
        url: '/v1/user/unlink',
        success: function (response) {
        	console.log(response)
        },
        fail: function (error) {
          console.log(error)
        },
      })
      Kakao.Auth.setAccessToken(undefined)
    }
  }  
</script>


<!-- 구글 api 사용을 위한 스크립트 -->
<script>
//처음 실행하는 함수
function init() {
	gapi.load('auth2', function() {
		gapi.auth2.init();
		options = new gapi.auth2.SigninOptionsBuilder();
		options.setPrompt('select_account');
        // 추가는 Oauth 승인 권한 추가 후 띄어쓰기 기준으로 추가
		options.setScope('email profile openid https://www.googleapis.com/auth/user.birthday.read');
        // 인스턴스의 함수 호출 - element에 로그인 기능 추가
        // GgCustomLogin은 li태그안에 있는 ID, 위에 설정한 options와 아래 성공,실패시 실행하는 함수들
		gapi.auth2.getAuthInstance().attachClickHandler('GgCustomLogin', options, onSignIn, onSignInFailure);
	})
}

function onSignIn(googleUser) {
	var access_token = googleUser.getAuthResponse().access_token
	$.ajax({
    	// people api를 이용하여 프로필 및 생년월일에 대한 선택동의후 가져온다.
		url: 'https://people.googleapis.com/v1/people/me'
        // key에 자신의 API 키를 넣습니다.
		, data: {personFields:'birthdays', key:'AIzaSyCC8gzwojhQfclUfYk4VbdfIQ_pzQ1Je0Ea', 'access_token': access_token}
		, method:'GET'
	})
	.done(function(e){
        //프로필을 가져온다.
		let profile = googleUser.getBasicProfile();
		console.dir(profile)
		let type="google";
		let id= profile.sT;
		let email=profile.Tt;
		let nickname= profile.Re;
		
		snsLoginProcess(type, id, email,nickname)
        
	})
	.fail(function(e){
		console.log(e);
	})
}
function onSignInFailure(t){		
	console.log(t);
}
</script>
<!-- 구글 api 사용을 위한 스크립트 -->




<script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>



<%@ include file="../common/footer.jsp" %>

 

 

 

 

SNSController

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.project.localbatter.dto.UserDTO;
import com.project.localbatter.entity.UserEntity;
import com.project.localbatter.repositories.UserRepository;
import com.project.localbatter.services.UserService;

import lombok.RequiredArgsConstructor;

@Controller
@RequiredArgsConstructor
public class SNSController {
	
	private final static Logger log = LogManager.getLogger();

	private final UserRepository userRepository;
	
	 private final UserService userService;
    
	@RequestMapping("/naver")
	public String naver() {
		return "/sns/naver";
	}
	
	@RequestMapping("/facebook")
	public String facebook() {
		return "/sns/facebook";
	}
	
	@RequestMapping("/sns/naverCallback")
	public String callback() {
		return "/sns/naverCallback";
	}
	
	
	@GetMapping("/sns/naverLoginProcess")
	public String naverLoginProcess(HttpSession session, UserDTO vo, RedirectAttributes rttr) {
		Object snsObjet=session.getAttribute("snsObjet");
		if(snsObjet==null) return "redirect:/";
	
		String snsType="";
		String snsId="";
		String email="";
		String nickname="";
		String phoneNum="";
		try {
			JSONParser jsonParser = new JSONParser();
			JSONObject jsonObject = (JSONObject) jsonParser.parse(snsObjet.toString());
			
			snsType="naver";
			snsId=jsonObject.get("id").toString();
			email=jsonObject.get("email").toString();
			nickname=jsonObject.get("nickname").toString();
			phoneNum=jsonObject.get("mobile").toString();
			log.info(" 등록할 정보 :  {} , {} , {},  {} , {} " , snsType ,snsId ,email , nickname, phoneNum);
			
			
			UserEntity userEntity = userRepository.findByUsername(email).get();
			Authentication authentication = new UsernamePasswordAuthenticationToken(userEntity, userEntity.getPassword(), userEntity.getAuthorities());
            SecurityContext securityContext = SecurityContextHolder.getContext();
            
            securityContext.setAuthentication(authentication);
            session.setAttribute("g_user", userEntity);       
            
            session.removeAttribute("snsObjet");                    
          
		} catch (Exception e) {
			//rttr.addFlashAttribute("naverError","등록되지 않은 회원입니다.");		
			//등록된 이메일 존재하지 않을 경우 회원가입 처리 후 로그인
			vo.setUsername(email);
			vo.setNickname(nickname);
			vo.setPhone(phoneNum);
			vo.setSnsType(snsType);
			vo.setSnsId(snsId);
			vo.setPassword(snsType+email+snsId);//임의 비밀번호
			
			userService.userSave(vo);
			
			//로그인 처리
			UserEntity userEntity = userRepository.findByUsername(email).get();
			Authentication authentication = new UsernamePasswordAuthenticationToken(userEntity, userEntity.getPassword(), userEntity.getAuthorities());
            SecurityContext securityContext = SecurityContextHolder.getContext();
            
            securityContext.setAuthentication(authentication);
            session.setAttribute("g_user", userEntity);       
            
            session.removeAttribute("snsObjet");           
		}
		 return "redirect:/";   

	}

	//구글, 카카오
	// REST API의 조건(쿠키 기반의 세션 처리)에는 더 이상 CSRF이 관련이 없으므로 이러한 API는 CSRF 공격을 받을 가능성이 존재하지 않는다.
	@PostMapping("/sns/snsLoginProcess")
	@ResponseBody
	public Map<String, Object> snsLoginProcess(HttpSession session, @RequestParam  Map<String, String> param,  UserDTO vo) throws JsonProcessingException{
		Map<String, Object> resultMap=new  HashMap<String, Object>();
		resultMap.put("status", "error");
		
		log.info(" param :  {} " ,  param.toString());
		
		
		if(param.get("email")!=null && !param.get("email").equals("") &&  param.get("snsId")!=null && !param.get("snsId").equals("") ) {
			
			try {
				//등록된 이메일 존재시 로그인 처리
		     	UserEntity userEntity = userRepository.findByUsername(param.get("email")).get();	
	    		Authentication authentication = new UsernamePasswordAuthenticationToken(userEntity, userEntity.getPassword(), userEntity.getAuthorities());
	            SecurityContext securityContext = SecurityContextHolder.getContext();
	            
	            securityContext.setAuthentication(authentication);
	            session.setAttribute("g_user", userEntity);       
	                             	           
	            resultMap.put("status", "success");
			}catch (Exception e) {
				
				try {
					//등록된 이메일 존재하지 않을 경우 회원가입 처리 후 로그인
					vo.setUsername(param.get("email"));
					vo.setNickname(param.get("nickname"));
					vo.setPhone(param.get("phoneNum"));
					vo.setSnsType(param.get("snsType"));
					vo.setSnsId(param.get("snsId"));
					vo.setPassword(param.get("snsType")+param.get("email")+param.get("snsId"));//임의 비밀번호
					userService.userSave(vo);
					
					//로그인 처리
					UserEntity userEntity = userRepository.findByUsername(param.get("email")).get();
					Authentication authentication = new UsernamePasswordAuthenticationToken(userEntity, userEntity.getPassword(), userEntity.getAuthorities());
		            SecurityContext securityContext = SecurityContextHolder.getContext();
		            
		            securityContext.setAuthentication(authentication);
		            session.setAttribute("g_user", userEntity);  
		            
		            resultMap.put("status", "success");
				}catch (Exception e2) {					
					resultMap.put("status", "error");
				}    			
			}	    
		}
		return resultMap;
	}
		
	
	

}

 

 

네이버  -  자바로 개발

pom.xml 

		<dependency>
			<groupId>com.googlecode.json-simple</groupId>
			<artifactId>json-simple</artifactId>
			<version>1.1.1</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.10.1</version>
		</dependency>

 

NaverApiExamMemberProfile

 

//네이버 API 예제 - 회원프로필 조회
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service;

import com.project.localbatter.components.GenerateFile;
import com.project.localbatter.components.PagingUtil;
import com.project.localbatter.entity.UserEntity;
import com.project.localbatter.repositories.ProfileRepository;
import com.project.localbatter.repositories.UserRepository;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;

@Configuration
public class NaverApiExamMemberProfile {
	 
	   private final static Logger log = LogManager.getLogger();
	   
	   public String  getInfo(String jsonData, HttpServletRequest request) {
		   
		    JSONParser jsonParser = new JSONParser();
			try {
				JSONObject jsonObject = (JSONObject) jsonParser.parse(jsonData);
				//System.out.println("\n\n\n jsonObject : " +jsonObject.toString());
				//System.out.println("\n\n\n access_token : " +jsonObject.get("access_token"));
				
			    String token=(String)jsonObject.get("access_token"); 				   
		        String header = "Bearer " + token; // Bearer 다음에 공백 추가
		        String apiURL = "https://openapi.naver.com/v1/nid/me";


		        Map<String, String> requestHeaders = new HashMap<>();
		        requestHeaders.put("Authorization", header);
		        String responseBody = get(apiURL,requestHeaders);
		        
		        log.info("responseBody  :  {} ", responseBody); 
		        
		        JSONParser jsonParser2 = new JSONParser();
		    	JSONObject resObj = (JSONObject) jsonParser2.parse(responseBody);
		    	String obj1=resObj.get("response").toString();

		    	
		    	log.info("** obj1  :   {}" ,obj1);
		    	
		    	
		    	JSONParser jsonParser3 = new JSONParser();
		    	JSONObject resObj2 = (JSONObject) jsonParser3.parse(obj1);
		    	String email=resObj2.get("email").toString();		    	

		    	System.out.println("** email  : " +email);		    	
		    	//return email;
		    	return resObj2.toString();	
		    	
			} catch (ParseException e) {
				e.printStackTrace();				
				return null;
			}
			
	   }

	   
	    private static String get(String apiUrl, Map<String, String> requestHeaders){
	        HttpURLConnection con = connect(apiUrl);
	        try {
	            con.setRequestMethod("GET");
	            for(Map.Entry<String, String> header :requestHeaders.entrySet()) {
	                con.setRequestProperty(header.getKey(), header.getValue());
	            }


	            int responseCode = con.getResponseCode();
	            if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출
	                return readBody(con.getInputStream());
	            } else { // 에러 발생
	                return readBody(con.getErrorStream());
	            }
	        } catch (IOException e) {
	            throw new RuntimeException("API 요청과 응답 실패", e);
	        } finally {
	            con.disconnect();
	        }
	    }


	    private static HttpURLConnection connect(String apiUrl){
	        try {
	            URL url = new URL(apiUrl);
	            return (HttpURLConnection)url.openConnection();
	        } catch (MalformedURLException e) {
	            throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
	        } catch (IOException e) {
	            throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
	        }
	    }


	    private static String readBody(InputStream body){
	        InputStreamReader streamReader = new InputStreamReader(body);


	        try (BufferedReader lineReader = new BufferedReader(streamReader)) {
	            StringBuilder responseBody = new StringBuilder();


	            String line;
	            while ((line = lineReader.readLine()) != null) {
	                responseBody.append(line);
	            }


	            return responseBody.toString();
	        } catch (IOException e) {
	            throw new RuntimeException("API 응답을 읽는데 실패했습니다.", e);
	        }
	    }


	
}

 

 

naver.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.security.SecureRandom" %>
<%@ page import="java.math.BigInteger" %>
<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <title>네이버 로그인</title>
  <script type="text/javascript" src="https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
  <!-- 네이버아이디로로그인 버튼 노출 영역 -->
  <div id="naver_id_login"></div>
  <!-- //네이버아이디로로그인 버튼 노출 영역 -->
  <script type="text/javascript">
  	var naver_id_login = new naver_id_login("iDRiqlC13V1cqQUU29LatV", "http://localhost:8000/sns/naverCallback");
  	var state = naver_id_login.getUniqState();
  	naver_id_login.setButton("white", 2,40);
  	naver_id_login.setDomain("YOUR_SERVICE_URL");
  	naver_id_login.setState(state);
  	naver_id_login.setPopup();
  	naver_id_login.init_naver_id_login();
  </script>
</html>

 

naverCallback.jsp

<%@page import="com.project.localbatter.config.NaverApiExamMemberProfile"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.net.URL" %>
<%@ page import="java.net.HttpURLConnection" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<html>
  <head>
    <title>네이버로그인</title>
  </head>
  <body>
  <%
    String clientId = "iDRiqlC1V1cqQ2UU9LatV";//애플리케이션 클라이언트 아이디값";
    String clientSecret = "ToHePA4_og";//애플리케이션 클라이언트 시크릿값";
    String code = request.getParameter("code");
    String state = request.getParameter("state");
    String redirectURI = URLEncoder.encode("http://localhost:8000/sns/naverCallback", "UTF-8");
    String apiURL;
    apiURL = "https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&";
    apiURL += "client_id=" + clientId;
    apiURL += "&client_secret=" + clientSecret;
    apiURL += "&redirect_uri=" + redirectURI;
    apiURL += "&code=" + code;
    apiURL += "&state=" + state;
    String access_token = "";
    String refresh_token = "";
    System.out.println("apiURL="+apiURL);
    try {
      URL url = new URL(apiURL);
      HttpURLConnection con = (HttpURLConnection)url.openConnection();
      con.setRequestMethod("GET");
      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()));
      }
      String inputLine;
      StringBuffer res = new StringBuffer();
      while ((inputLine = br.readLine()) != null) {
        res.append(inputLine);
      }
      br.close();
      if(responseCode==200) {
          
          
     	   out.print("로그인 토큰");       
      	   out.println(res.toString());
   
	       String result=new NaverApiExamMemberProfile().getInfo(res.toString(), request);
	       out.println("<br><br>로그인 성공 : "+ result);
	       if(result!=null &&  !result.equals("")){
	    	
	    	   session.setAttribute("snsObjet", result);
	    	   response.sendRedirect("/sns/naverLoginProcess");
	       }else{
	    	   out.println("로그인 실패");
	       }
    	         
      }
      
    } catch (Exception e) {
      System.out.println(e);
    }
  %>
  </body>
</html>

 

 

 

about author

PHRASE

Level 60  라이트

뒤로 오는 호랑이는 속여도 앞으로 오는 팔자는 못 속인다 , 운명은 맘대로 할 수 없다는 말.

댓글 ( 4)

댓글 남기기

작성