mjeongriver
article thumbnail
Published 2023. 2. 23. 18:05
day92-spring boot TIL/Spring boot

1. 어제 이어서 로그인, 마이 페이지

 

마이페이지 치고 들어가도 로그인 페이지로 진입하게 됨. 단점: 페이지가 50개일 때 하나씩 다 넣어줘야 하는 번거로움이 있음

 

1) 인터셉터

- 위와 같은 단점으로 인터셉터 개념 사용

- 인터셉터는 컨트롤러 들어가기 직전에 요청을 가로채서 검사를 해줄 수 있는 기능

- 필터와 인터셉터의 개념은 똑같으나 위치가 다르다는 차이점이 존재함

- 부가적으로 AOP는 필터 개념은 아니고, 컨트롤러나 메서드가 실행될 때마다 검사를 하고 싶을 때 사용할 수 있는 기능

- 로그, 트랙잭션 같은 개념이 AOP에 속함

 

filter: 아예 맨 처음에 진입 장벽을 세워서 모든 요청을 거를 수 있음(security라는 개념과 같이 사용 됨-아예 앞단에서 막아버림)

 

- 인터셉터의 사용은 HandlerInterceptor 인터페이스(2번째 사진에 3, 6, 9번-3,6만 자주 사용 됨)를 상속 받아 사용함.

- 3번은 진입 전에 요청을 받아서 확인 하는 것, 6번은 컨트롤러가 수행 되고 나서 내가 검사하고 싶은 기능이 있으면 사용, 9번은 마지막(최종 뷰로 넘어가기 전에 검사할 수 있음-굳이 사용하지는 않음)

 

2) 인터셉터 설정

 

 

* 적용 - UserAuthHandler, webconfig, UserSuccessHandler

 

더보기

- UserAuthHandler

package com.simple.basic.util;

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

import org.springframework.web.servlet.HandlerInterceptor;

public class UserAuthHandler implements HandlerInterceptor {

	/*
	 * 1. HandlerIntercetpor를 상속 받습니다.
	 * 
	 * preHandle - 컨트롤러 진입 전에 실행
	 * postHandle - 컨트롤러 수행 후에 실행
	 * afterCompletion - 화면으로 가기 직전에 수행
	 * 
	 * 2. 인터셉터 클래스를 bean으로 등록
	 */
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	
		System.out.println("인터셉터 실행");
		
		//현재 세션을 얻음
		HttpSession session = request.getSession();
		String user_id = (String)session.getAttribute("user_id");
		
		if(user_id == null) { //로그인이 안됨
			response.sendRedirect( request.getContextPath() + "/user/login" ); //로그인 페이지로 리디렉션 
			return false; //컨트롤러를 실행하지 않음
		}
		
		return true; //컨트롤러 실행
	
	}
	
}

 

- webconfig

package com.simple.basic.config;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.simple.basic.controller.HomeController;
import com.simple.basic.util.UserAuthHandler;
import com.simple.basic.util.UserSuccessHandler;


@Configuration //개별적인 스프링 빈 설정 파일
public class WebConfig implements WebMvcConfigurer {
	
	//빈을 보관하고 있는 장소 (스프링 컨테이너)
	/*
	@Autowired
	ApplicationContext applicationContext;
	
	//properties파일에 선언된 변수를 바로 참조
	@Value("${server.port}")
	String port;
	
	@Bean //해당 메서드 실행하게됨
	public void test() {
		
		TestBean t = applicationContext.getBean(TestBean.class);
		System.out.println(t);
		
		HomeController h = applicationContext.getBean(HomeController.class);
		System.out.println(h);
		
		int c = applicationContext.getBeanDefinitionCount();
		System.out.println("빈의개수:" + c);
		
		System.out.println("properties에 선언된값:" + port);
	}
	
	@Bean //해당 메서드 실행하게됨
	public TestBean testBean() {
		return new TestBean(); //빈으로 등록
	}
	*/
	
	//프리 핸들러
	@Bean
	public UserAuthHandler userAuthHandler() {
		return new UserAuthHandler();
	}
	
	//포스트 핸들러
	@Bean
	public UserSuccessHandler userSuccessHandler() {
		return new UserSuccessHandler();
	}

	//WebMvcConfigurer클래스가 제공해주는 인터셉터 추가 함수
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		
		//프리 핸들러
		registry.addInterceptor(userAuthHandler() )
//				.addPathPatterns( Arrays.asList("경로", "경로", "경로", "경로"))
				.addPathPatterns("/user/*") //패스 경로 포함
				.excludePathPatterns("/user/login"); //제외 하고 싶은 경로(패스 경로 제외)
	
		//경로 별로 인터셉터를 다르게 등록
		//포스트 핸들러
		registry.addInterceptor( userSuccessHandler() )
				.addPathPatterns("/user/*");
	}
	
	
}

 

- UserSuccessHandler

package com.simple.basic.util;

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

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class UserSuccessHandler implements HandlerInterceptor {

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		//modelAndView은 컨트롤러에서 model에 담은 데이터도 확인이 가능합니다.
		System.out.println("포스트 핸들러:" + request.getRequestURI());
	}
	
	
}

 

- bootmyweb에 적용해보기

 

3번째는 위에꺼 그대로 가져올 것

 

주석처리 하면 로그인 안하면 home화면, 다른 화면 진입 불가

 

 

* Webconfig, UserController, UserAuthHandler, menuHandler, basiclayout

더보기

- Webconfig

package com.coding404.myweb.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.coding404.myweb.util.interceptor.MenuHandler;
import com.coding404.myweb.util.interceptor.UserAuthHandler;

@Configuration //스프링 설정 파일
public class WebConfig implements WebMvcConfigurer {

	//프리 핸들러
	@Bean
	public UserAuthHandler userAuthHandler() {
		return new UserAuthHandler();
	}

	//포스트 핸들러
	@Bean
	public MenuHandler menuHandler() {
		return new MenuHandler();
	}
	
	//인터셉터 추가
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor( userAuthHandler() )
				.addPathPatterns("/main")
				.addPathPatterns("/product/*")
				.addPathPatterns("/user/*")
				.excludePathPatterns("/user/login")
				.excludePathPatterns("/user/join");
		
//				.addPathPatterns("/**")
//				.excludePathPatterns("/user/login")
//				.excludePathPatterns("/user/join")
//				.excludePathPatterns("/js/*")
//				.excludePathPatterns("/css/*")
//				.excludePathPatterns("/img/*");
				//REST API 패스에서 제외
		
		registry.addInterceptor(menuHandler() )
				.addPathPatterns("/main")
				.addPathPatterns("/product/*")
				.addPathPatterns("/user/*");
	}
}

 

- UserController

package com.coding404.myweb.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

	@GetMapping("/join")
	public String join() {
		return "user/join";
	}
	
	@GetMapping("/login")
	public String login() {
		return "user/login";
	}
	
	@GetMapping("/userDetail")
	public String userDetail() {
		return "user/userDetail";
	}
}

 

- UserAuthHandler

package com.coding404.myweb.util.interceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;

public class UserAuthHandler implements HandlerInterceptor {

	/*
	 * 1. HandlerIntercetpor를 상속 받습니다.
	 * 
	 * preHandle - 컨트롤러 진입 전에 실행
	 * postHandle - 컨트롤러 수행 후에 실행
	 * afterCompletion - 화면으로 가기 직전에 수행
	 * 
	 * 2. 인터셉터 클래스를 bean으로 등록
	 */
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	
		System.out.println("인터셉터 실행");
		
		//현재 세션을 얻음
		HttpSession session = request.getSession();
		String user_id = (String)session.getAttribute("user_id");
		
		if(user_id == null) { //로그인이 안됨
			response.sendRedirect( request.getContextPath() + "/user/login" ); //로그인 페이지로 리디렉션 
			return false; //컨트롤러를 실행하지 않음
		}
		
		return true; //컨트롤러 실행
	}
}

 

- menuhandler

package com.coding404.myweb.util.interceptor;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.coding404.myweb.product.service.ProductMapper;

public class MenuHandler implements HandlerInterceptor {

	@Autowired
	private ProductMapper productMapper;
	
	//메뉴 핸들러
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		String uri = request.getRequestURI();
		request.setAttribute("uri", uri);
	}
}

 

- basiclayout - 맨 밑에 script 추가(확인할 때 인터셉터 잠깐 주석처리)하고 위에 밑에 사진 부분 추가

 

이렇게 하면 메뉴에 들어갔을 때 메뉴가 고정이 됩니다.

 

 

<script th:inline="javascript">
	
	/*
	메뉴선택유지 -
	sub_menu에 display:block.
	sub_menu > a링크에 on클래스.
	sub_menu_toggle > a에 sub_menu_select클래스.
	*/
	var menu = JSON.parse('[[${uri}]]'); //postHandler에서 보내주는 uri
	
	//1번
	//$("a[href*='" + menu + "']").addClass("on");
	//console.log($("a[href*='" + menu + "']") );
	
	//2번
	$(".sub_menu a").each(function(index, item) {
		//console.log(index, item)
		//console.log( $(item) )
		//console.log ( $(item).attr("href") )
		//href에 uri값이 들어있는지 확인
		if( $(item).attr("href").includes(menu) ) {
			 $(item).addClass("on"); //a태그에 on클래스 추가
			 $(item).closest(".sub_menu").css("display", "block");
			 $(item).closest(".sub_menu").prev().addClass("sub_menu_select");
		}
		
	})
	
</script>

 

2. 자바측 API 통신(vscode에서 ajax → js-index05.html)

 

카카오 developer 참고

 

 

- login 창에 제이쿼리 링크 추가

 

 

- login.html에 맨 마지막에 script 부분 추가

<script>
  	 $(".kakaoBtn").click(function(){
  		 
  		 http://127.0.0.1:8484/user/kakao
  		 //uri에는 web 사이트 도메인에 추가한 주소 + user/kakao
  		 location.href="https://kauth.kakao.com/oauth/authorize?client_id=본인의 restAPI &redirect_uri=http://127.0.0.1:8484/user/kakao&response_type=code";
  	 })
  </script>

 

- userController에 추가

 

//카카오 redirect_uri 값 추가
	@GetMapping("/kakao")
	public String kakao(@RequestParam("code") String code) {
		
		System.out.println(code);

		return null;
	}

 

- 본인 포트 번호 확인해서 넣을 것

 

 

* 하고 나서 카카오 디벨로퍼 로그아웃을 해야지 로그인 창으로 넘어감

 

 

- kakao API에 @Component - 카카오라는 이름으로 빈 생성

 

 

- userController에 Autowired 걸고 kakao 변수 선언

@Autowired
	private KakaoAPI kakao;

 

* KakaoAPI

package com.coding404.myweb.util;

import org.springframework.stereotype.Component;

@Component("kakao")
public class KakaoAPI {

	//토큰 발급 기능
	public String getAccessToken(String code) {
		
		return null;
	}
	
}

 

- 카카오 디벨로퍼에서 토큰 받기

form 방식 

 

package com.coding404.myweb.util;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.springframework.stereotype.Component;

@Component("kakao")
public class KakaoAPI {

	//토큰 발급 기능
	public String getAccessToken(String code) {
		
		//post의 폼데이터 형식 키=값&키=값..
		String requestURL = "https://kauth.kakao.com/oauth/token";
		String redirect_url ="http://127.0.0.1:8484/user/kakao";
		
		String data = "grant_type=authorization_code" 
					+ "&client_id=본인의 restAPI 주소"
					+ "&redirect_uri=" + redirect_url
					+ "&code=" + code;
		
		try {
			
						URL url = new URL(requestURL);
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();
			
			conn.setRequestMethod("POST"); //포스트 형식
			conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
			
			//데이터 전송을 위한 클래스
//			OutputStream out = conn.getOutputStream();
//			OutputStreamWriter osw = new OutputStreamWriter(out);
//			BufferedWriter br = new BufferedWriter(osw);
			
			BufferedWriter br = new BufferedWriter( new OutputStreamWriter( conn.getOutputStream()));
			
			br.write(data); //쓰고
			br.flush(); //밀어내고
			
			//응답 결과를 conn 객체로 받음
			System.out.println( conn.getResponseCode() );
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
}

 

- 그 다음에 컨트롤러에서 확인해볼 것

	//카카오 redirect_uri 값 추가
	@GetMapping("/kakao")
	public String kakao(@RequestParam("code") String code) {
		
		System.out.println("인가코드:" + code);
		
		String token = Kakao.getAccessToken(code);

		return "redirect:/main";
	}

 

- 다시 kakaoAPI

 

//응답 결과를 conn 객체로 받음
			System.out.println( "요청 결과:" + conn.getResponseCode() );
			
			if(conn.getResponseCode() == 200) { //요청이 성공
				
				BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));
				
				String result ="";
				String str = null;
				while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
					result += str;
				}
				
				System.out.println(result);
				
				
			}

이 모형이 온거임, 여기서 파란색 뽑아야 함

 

gson 사용해서 문자열 추출 할 것(2.85) - build gradle에 추가 후 refresh gradle

 

 

//json 데이터 분해
				JsonParser json = new JsonParser(); //com.google.~
				JsonElement element = json.parse(result); //json 데이터 전달
				JsonObject obj = element.getAsJsonObject(); //json 오브젝트 형변환
				String access_token = obj.get("access_token").getAsString();
				String refresh_token = obj.get("refresh_token").getAsString();

//카카오 redirect_uri 값 추가
	@GetMapping("/kakao")
	public String kakao(@RequestParam("code") String code) {
		
		System.out.println("인가코드:" + code);
		
		String token = Kakao.getAccessToken(code);
		
		System.out.println("어세스 토큰:"+ token);

		return "redirect:/main";
	}

컨트롤러에서 어세스 토큰 받으면 console 결과창에 나옴(서버 꼭 껐다가 켤 것!)
2번째 단계 여기까지 한거임(이제 토큰으로 사용자 정보 빼올 수 있음)

 

- 이제 토큰 기반으로 유저 정보 얻기

 

 

- kakaoapi에 추가

//토큰 기반으로 유저 정보 얻기
	public Map<String, Object> getUserInfo(String access_token){
		
		String requestURL = "https://kapi.kakao.com/v2/user/me";

		try {

			URL url = new URL(requestURL);
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();

			conn.setRequestMethod("POST"); //포스트 형식
			conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
			
			//헤더에 토큰 정보를 추가
			conn.setRequestProperty("Authorization", "Bearer " + access_token);
			
			System.out.println("토큰 요청 결과:" + conn.getResponseCode());
			
			if(conn.getResponseCode() == 200) { //사용자 데이터 요청 성공
				BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));

				String result ="";
				String str = null;
				while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
					result += str;
				}
				
				System.out.println(result);
			}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}

 

- 컨트롤러에서 출력

	//카카오 redirect_uri 값 추가
	@GetMapping("/kakao")
	public String kakao(@RequestParam("code") String code) {
		
		System.out.println("인가코드:" + code);
		
		String token = Kakao.getAccessToken(code);
		
		System.out.println("어세스 토큰:"+ token);
		
		Map<String, Object> map = Kakao.getUserInfo(token);

		return "redirect:/main";
	}
}

사용자 정보를 알 수 있음

 

이 방법 사용해서 내용 얻어올 수 있음!

 

- kakaoAPI

	//토큰 기반으로 유저 정보 얻기
	public Map<String, Object> getUserInfo(String access_token){
		
		//데이터를 저장할 map
		Map<String, Object> map = new HashMap<>();
		String requestURL = "https://kapi.kakao.com/v2/user/me";
		

		try {

			URL url = new URL(requestURL);
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();

			conn.setRequestMethod("POST"); //포스트 형식
			conn.setDoOutput(true); //카카오 서버로부터 데이터 응답을 허용
			
			//헤더에 토큰 정보를 추가
			conn.setRequestProperty("Authorization", "Bearer " + access_token);
			
			System.out.println("토큰 요청 결과:" + conn.getResponseCode());
			
			if(conn.getResponseCode() == 200) { //사용자 데이터 요청 성공
				BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream()));

				String result ="";
				String str = null;
				while( (str = br.readLine() ) != null) { //데이터 한줄씩 읽음 - 읽을 값이 없다면 null을 반환
					result += str;
				}
				
				System.out.println(result);
				
		        JsonParser json = new JsonParser();
		        JsonElement element = json.parse(result);
		        
		        //json에서 key를 꺼내고, 다시 key를 꺼낸다.
		        JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
		        JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
		        
		        String nickname = properties.getAsJsonObject().get("nickname").getAsString();
		        String email = kakao_account.getAsJsonObject().get("email").getAsString();
			
		        map.put("nickname", nickname);
		        map.put("email", email);
			}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return map;
	}

 

- 하고 컨트롤러

사용자 데이터 map으로 저장해서 뿌리면 얻을 수 있음

 

'TIL > Spring boot' 카테고리의 다른 글

windows에서 java 환경변수 설정하기  (0) 2023.06.12
day91-spring boot  (0) 2023.02.22
day90-spring boot  (0) 2023.02.21
day88-spring boot  (0) 2023.02.17
day86-spring boot  (0) 2023.02.16
profile

mjeongriver

@mjeongriver

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그