✅ Vue활용하기

#️⃣ vue의 시작점인 AngularJs의 탄생이유

자바스크립트와 ajax를 활용하면서 화면깜빡임없이 전환이 가능해졌다.

점점 한번만 로드해서 화면전환을 하려 함. (Single Page Application)

ajax를 가장많이 쓰는 회사 == 구글

react는 oneway방식이라 변수값이 변해도 직접 참조를 해야 쓸 수 있음

vue와 angularJS는 twoway방식이라 한번 바인딩하면 변수값이 바꼈을때 저절로 변경됨

 

👉 Angular JS는 자바스크립트 실행환경 (mvc와는 관련 없음)

👉 VUE는 자바스크립트를 mvc로 개발하게 해주는 라이브러리 (mvc를 쓸게 아니면 필요없음)

👉  반대로 백엔드를 mvc로 개발하게 해주는 라이브러리 Spring Library

👉 mvc의 장점 == 모델을 바인딩 하는 방법으로 DOM을 대신할 수 있다.

 

 

 

✅ MVC(W) 패턴의 이해. Model 기반 코드

#️⃣ VUE 라이브러리 다운받기

 

 

Introduction | Vue.js

VueConf Toronto - Join the premier Vue.js conference | 9-10 Nov 2023 - Toronto, CanadaView Schedule Use code VUEJS to get 15% off

vuejs.org

🚫 리액트나 앵귤러는 cdn으로 쓸 수 없다.

 

 

🔥 바인드 하는 방법

 

API Reference | Vue.js

VueConf Toronto - Join the premier Vue.js conference | 9-10 Nov 2023 - Toronto, CanadaView Schedule Use code VUEJS to get 15% off

vuejs.org

 

✔️ v-text="x"

<body id="app">
    <header class="header md:header">
        <div class="content-box">
            <h1><a href="/index.html" v-text="x"></a></h1>

 

✔️ v-model="x" ▶ value 값을 바꾸게 되어있음. 투웨이방식!

인풋박스에서 값을 바꾸면 화면에 바인딩해놓은 값들도 같이 바뀐다

 

 

✅ 로그인 식별자 만들기

회원이 로그인 할 때는 회원만이 사용할 이름 (일반적으로 id) 가 필요하다.

 

 

 

 

@Service
public class MemberServiceImp implements MemberService {

	@Autowired
	private MemberRepository repository;

	@Override
	public Boolean inValid(String username, String password) {
		// 여기서 리파지토리에게 업무를 맡기면 안된다
		// 리파지토리에 해당되는 crud만 조회하도록 한다

//		repository.findbyId(1L);
		Member member = repository.findByNickName(username); // username은 사용자가 만든 아이디
		// 멤버 정보가 널이거나, 멤버정보가 있어도 패스워드가 맞지 않으면 리턴시킨다
		if (member == null)
			return false;
		else if (!member.getPassword().equals(password))
			return false;

		return true;
	}
}

@PostMapping("login")

public String login(String username, String password, HttpSession session) {

// 로그인을 처리하는 실질적인 코드영역

// 두가지 경로.

// 1) 가다가 걸려서 왔으면 인증하고 거기로 다시 return

// 2) 자발적으로 로그인 하러 왔으면 로그인 후 이동하는 위치 지정해주기

 

if (service.inValid(username, password)) {

session.setAttribute("username", username);

// 포스트 요청으로 온 사람은 뷰페이지로 가면 안되고 무조건 리디렉션

return "redirect:/member/index";

}

System.out.println(session.getAttribute("username"));

return "redirect:/user/login?error";

 

}

<form accept="login" method="post">
    <div th:class="${param.error}? 'd:block' : 'd:none'" style="color:red;">
    
//에러임을 알려주는 파라미터를 넣어놓으면 타임리프로 받아서 오류 문구를 표기할 수 있다(클래스 바꿔끼기)

 

 

✅ 권한

1. 인증한것만으로도 권한을 줌

2. 인증 + 권한을 둘다 감별 (인증 했구나. 그럼 너의 권한은 뭐니?) - 회원 레벨에 따라서 볼 수 있는 레벨이 다름 ▶ 오류페이지를 반환하면서 403 오류를 찍어줌

월드 와이드 웹에 쓰이는 HTTP 프로토콜에서 HTTP 403, 403 Forbidden은 서버가 허용하지 않는 웹 페이지나 미디어를 사용자가 요청할 때 웹 서버가 반환하는 HTTP 상태 코드

 

#️⃣ return URL

로그인 전에 있던 곳으로 다시 보내기 : return url

👉 폼태그 안에 hidden으로 숨겨서 returnURL 파라미터를 넘길 수 있다

 

폼태그 안에&nbsp; returnURL 숨기기
이런 형태로 만든 이유는 우리가 쓸 라이브러리가 이런 조건을 요구하기때문 !

 

 

 

 

 

 

 

 

✅ NodeJs배경

 

자바스크립트는 브라우저가 있어야만 실행가능하다. ▶ 불편함

브라우저없이도 실행할 수 있는 환경이 생겨남 ▶ NodeJs

 

NodeJs는 V8엔진(브라우저에서 돌아가던 엔진)을 가지고있으면서 스크립트 언어를 올려서 브라우저 없이 돌아갈 수 있게 해준다. == 브라우저가 없으므로 스크립트가 이용할수있던 document언어가 없음.

document객체가 없더라도 사용할 수 있는 도구가 필요함.

자바가 자바실행환경이 있듯이, JS도 자바스크립트의 로컬 실행환경으로 NodeJs를 사용함으로써 독자적으로 개발할 수 있게 됨.

이때 자바스크립트를 위한 저장소가 NPM

 

 

 

npm | Home

Bring the best of open source to you, your team, and your company Relied upon by more than 17 million developers worldwide, npm is committed to making JavaScript development elegant, productive, and safe. The free npm Registry has become the center of Java

www.npmjs.com

 

자바스크립트도 로컬에서 실행할 수 있게 되었다

 

NodeJs에서 스크립트를 실행할 수 있지만 DOM을 사용할 수는 없다. (console.log는 찍을 수 있다)

 

 

 

 

 

✅ Node Api

스프링역할을 하는것 : express

 

 

 

 

✅ 쿠키의 장점

한번 서버가 저장을 하고 보내주면 url 달라도 쿠키가 적용될 수 있다.(항상 가져옴. 단 하위페이지에 부여한건 상위페이지에서 가져다 쓸 수 없다)

 

 

 

#️⃣ 서버에서 쿠키 꺼내쓰기

1. 맨땅으로 꺼내기 - 반복문으로 찾아야 한다

//MVC MenuController.java 
@RequestMapping("detail")
public String detail(Model model, HttpServletRequest request, @RequestParam String id) {
    Long mId = Long.parseLong(id);
    Menu menu = service.getById(mId);
    System.out.println(menu);
    model.addAttribute("menu", menu);

    //쿠키는 꺼낼때 덩어리로 꺼내서 찾아야한다는 단점이 있다
    Cookie[] cookies = request.getCookies();

    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("cookietest")) {
                System.out.println("Cookie Name: " + cookie.getName());
                System.out.println("Cookie Value: " + cookie.getValue());
                break;
            }
        }
    } else {
        System.out.println("No cookies found in the request.");
    }

    return "menu/detail";
}

 

  • 쿠키 안에 String외에 배열, 엔티티 등을 심을수있을까? 🚫
  • 전달방식 자체가 url 기반의 문자열 ⭕ 이므로 문자열만 가능하다
  • url 인코딩방식으로 쿠키를 심고 꺼내 쓸때도 디코딩을 해야한다. 만약 스프링 어노테이션인 @CookieValue를 쓴다면 디코딩도 자동으로 됨!
  • 쿠키는 루트페이지에서 전달해야 하위페이지도 적용됨

 

 

2. 스프링으로 꺼내기 (@CookieValue)

	@RequestMapping("detail")
	public String detail(@CookieValue String cookietest, Model model, @RequestParam Long id) {
    
    //HttpServletRequest request --어노테이션으로 뽑으면 서블릿을 불러올 필요가없음
	
    	System.out.println(cookietest);
		System.out.println("나와라");
		
		Menu menu = service.getById(id);
		model.addAttribute("menu", menu);

		//쿠키는 꺼낼때 덩어리로 꺼내서 찾아야한다는 단점이 있다
//		Cookie[] cookies = request.getCookies();
//		
//		if (cookies != null) {
//			for (Cookie cookie : cookies) {
//				if (cookie.getName().equals("cookietest")) {
//					System.out.println("Cookie Name: " + cookie.getName());
//					System.out.println("Cookie Value: " + cookie.getValue());
//					break;
//				}
//			}
//		} else {
//			System.out.println("No cookies found in the request.");
//		}

		return "menu/detail";
	}

 

👉 이때 파라미터 내 순서에서 @CookieValue가 마지막이라면, 출력순서도 마지막이 되어야한다. 다른 파라미터 출력값보다 쿠키출력이 먼저 나오면 콘솔에 찍히지않음! 파라미터를 한번에 받아서 처리한다고 생각했는데 파라미터도 순서대로 받아서 출력처리한다는걸 새삼깨달았다...

 

 

 

 

 

#️⃣ 쿠키 사용 제약 조건

 

1) 쿠키가 적용될 범위 적용 (세션은 불가)

 

Cookie cookie = new Cookie("cookietest", "octap");
if (request.getCookies() == null) // 쿠키가 하나라도 없을때 응답할때 쿠키를 부여한다
    response.addCookie(cookie);
cookie.setPath("/menu"); //쿠키가 지정될 경로(범위)를 지정할 수 있다
cookie.setMaxAge(1000000000); // 쿠키 생존시간 설정 (초단위이므로 계산해서 넣어야 함)

yamul에서 쿠키의 세션을 저장할 수 있다 (이때 설정키워드는 스프링부트 버전에 따라 다르며, 접미사를 붙이지 않으면 초단위임)

 

쿠키의 생존기간을 지정하지 않으면 세션과 동일하게 움직인다

 

 

 

2)  사용자 디스크에 저장된다

✔️ 쿠키는 기본적으로 현재 브라우저가 관리하는 프로세스 메모리에 저장된다.

👉 따라서 모든 브라우저를 다 닫아야 세션 키를 분실한다 (브라우저 하나를 닫는다고 해도 그 내부에 스레드가 수십개 움직이고있어서 프로세스가 죽는건 아니다)

 

✔️ 만약 쿠키의 저장기간을 1년이라고 하면 1년동안 컴퓨터를 끄지 않는이상 프로세스에 유지하기 힘드므로 이런경우는 디스크에 저장한다.

 

✔️ 쿠키는 클라이언트 디스크에 저장되므로 사용자에게 허용설정을 요청한다.

(* 어플리케이션은 모든 사용자를 위한 공간이라 덮어쓰기가 되므로 인증정보는 나만을 위한 공간인 세션이나 쿠키를 사용해야한다)

 

 

✅ 로그인 페이지 만들기

로그인에 들어가는경우 1) 로그인하려는 의도  2) 페이지를 보려고 했는데 로그인부터 하라고 요청받는 경우

 

@Controller
@RequestMapping("/member")
public class MemberController {

@GetMapping("index") //회원들이 들어가는 인덱스
public String login(HttpSession session) {

    //로그인페이지에서 담아주면 거기있는 세션을 가지고 검증
    Object username_= session.getAttribute("username");

    // 회원들 인덱스에 접속하려고 할 때- 너 인증은 하고 왔니? 안했으면 인증하고 와
    if (username_ ==null)
        return "redirect:/user/login";

    return "member/index"; 
}
<form accept="login" method="post"> //post method로 설정
    <fieldset>
        <legend class="d:none">인증정보</legend>
        <label class="d:none">아이디</label>
        <input type="text" name="username" placeholder="아이디"> //name으로 컨트롤러에 전송
        <label class="d:none">비밀번호</label>
        <input class="mt:3" name="password" type="password" placeholder="비밀번호">
    </fieldset>
    //제출버튼 생략
</form>
//UserController

@Controller
@RequestMapping("/user")
public class UserController {
	
    @GetMapping("login")
    public String login() {
            //여기는 데이터 필요없이 로그인 한다는 내용만있으므로 서비스가 필요없다
        return "user/login";
    }


    //유저네임과 패스워드를 파라미터로 입력받음 url은 login인 postMapping controller
    // 로그인을 처리하는 실질적인 코드
    @PostMapping("login")
    public String login(String username, String password) {
        // 로그인을 처리하는 실질적인 코드영역
        // 두가지 경로.
        // 1) 가다가 걸려서 왔으면 인증하고 거기로 다시 return
        // 2) 자발적으로 로그인 하러 왔으면 로그인 후 이동하는 위치 지정해주기

        if (service.inValid(username, password)) {
            session.setAttribute("username", username);
            // 포스트 요청으로 온 사람은 뷰페이지로 가면 안되고 무조건 리디렉션
            return "redirect: /user/index";
        }
        return "redirect:/user/login";
    }
}

 

 

✅ 스프링 시큐리티

: 스프링에서 제공하는 인증과 보안 관련 라이브러리

 

 

 

✅ 인증과 권한

1. 윈도우프로그램을 만들던 시절(클라이언트중심)

앱에서는 사용자가 사용자정보 (아이디와 패스워드)를 넣으면 어딘가에 남겨지게 되어있음.

사용자가 화면에 접근하려고 하면 인증이 있음/없음을 구별해서 사용하게 함

 

2. 현재 웹어플리케이션은

인증정보를 클라이언트가 아닌 서버가 저장하게 되어있음

html과 css만 다루는 환경에서는 다른메뉴를 클릭할 경우 ▶ 서버에요청 ▶ 서버에서 다른 페이지로 연결해줌. ▶요청에 대해서 그때그때 서블릿이 생겼었음.

 

3. 세션이 생긴 배경

서버에서 서블릿들은 생겼다 사라지지만 인증정보가 사라지면 안됨. 이때 활용할 수 있는  '계속 존재하는 공간'은 어플리케이션(서버에서 사용하는 전역변수공간)과 세션임 

 

이때 세션은 공간이라 생각하면 안됨. 정확학는 세션== '기간'을 뜻한다.

 

웹은 세션이란 기간을 두고 ,나랑 대화하는 사용자가 있다, 없다를 생각한다.

(사용자가 나를 다시 찾을지 여부에 대한 기다림의 기간. 여러 클라이언트로부터 페이지 요청을 받으므로 한 사용자에게 무한대로 접속 시간을 제공할 수 없다 & 보안문제!)

 

4. 세션이 기간인 이유

서버는 클라이언트 한명이 다섯번 요청한건지, 다섯명이 한번씩 요청한건지 알 수가 없음 ▶ 따라서 사용자를 위한 저장공간을 마련해야 한다.(해당 사용자가 하는 행위, 프로필정보 등을 저장하기 위해 전용공간인 세션을 설정할 수 밖에 없다) ▶ 사용자를 식별하는 방법이 필요하다 ▶ 공유기 ip를 가지고 식별이 불가함(사설아이피로 요청할 일이 없고 같은 공유기를 쓰면 그 집 컴퓨터는 다 같은 ip를 가진다)  ▶ 서버로부터 식별자가 발급된다 (SID발급)

 

  • 세션 == 사용기간 (자원 사용을 허락받은 시간)
  • 서버의 (세션)공간을 사용할 수 있다 (*사용할 자원이 있어야 한다)
  • 공간을 사용하기 위해서는 (세션)키가 필요하다. (이 키는 보안키/세션아이디/SID로도 불린다)
  • 톰캣의 default 세션 = 20분
  • 세션 타임아웃을 따로 설정할 수도 있다.

SID를 발급받은 클라이언트는 접속할때마다 해당 저장공간을 정해진 시간동안 사용할 수 있다. (ex. 세션이 유지되는 동안 페이지를 넘어다니며 장바구니에 값을 저장해둬도 초기화가 되지않는다)

 

 

 

#️⃣ Session 생성해보기

@Controller
@RequestMapping("/")
public class HomeController { //기본값으로 string을 설정해서 세션에 전달해봄
	
	@RequestMapping("index")
	public String index( @RequestParam (defaultValue="octap")String hello, HttpServletRequest request) {
		//서블릿이 다 죽어도 세션저장소는 키를 가진 사람만 쓸 수 있는 전역 공간이므로 죽지 않는다!
		HttpSession session = request.getSession();
		session.setAttribute("test",hello);
		return "index";
	}
}

처음 접속할때 서버로부터 cookie를 받는다
재접속할때는 쿠키값을 가지고 request한다

@Controller
@RequestMapping("/menu")
public class MenuController {

	@Autowired
	private MenuService service;

	@RequestMapping("list")
	public String list(Model model, HttpServletRequest request) {
		HttpSession session = request.getSession();
// 다른코드 생략
		System.out.println(session.getAttribute("test")); // 다른컨트롤러에서 넣은 test의 값이 나온다
		return "menu/list";
	}

👉 세션을 생성하지않으면 똑같이 접속해도 SID를 받질 않음! 개발자도구의 어플리케이션으로 가도 cookie를 확인할 수 없음!

👉 세션이 살아있는 동안은 어느 서블릿에서든 (다른 페이지에서도) 세션을 꺼내볼 수 있다. ▶ 세션키(SID)만 가지고 다니면 된다. (만약 세션키를 분실한다면 저장해놓은건 모두 잃어버림) -- 이때 세션키도 쿠키임!

 

 


 

 

#️⃣ 쿠키 개념

(** 개인화된 저장소는 쿠키와 세션으로 볼 수 있다.)

 

  • 쿠키는 브라우저에 or 클라이언트에 저장하는 값.
  • 서버가 저장하라고 알려준 값. (접속할때 처음만 설정되고 새로고침하면 사라짐)
  • 캐비넷 키와 동일.
  • 서버에 접속할때마다 가져가야함.
  • 전체적으로 SID와 설명이 유사한것같은데, SID도 쿠키에 담겨서 이동된다!

 

 

 

#️⃣ 쿠키 생성하기

  • 쿠키는 클라이언트가 가지고 있는 것. 
  • 응답헤더에 set cookie로 들어감으로써 처음으로 받고, 페이지에 request할 때마다 Cookie를 가져간다.
  • 그 이후로는 서버에서 response할때 cookie를 전달해줄 필요가 없다

 

@RequestMapping("list")
	public String list(Model model, HttpServletRequest request, HttpServletResponse response) {

		Menu menu = Menu.builder().engName("ame").build();

//코드생략

	Cookie cookie = new Cookie("cookietest", "octap");
			
		if (request.getCookies() ==null) // 쿠키가 하나라도 없을때 응답할때 쿠키를 부여한다
			response.addCookie(cookie);
		if(request.getCookies().length<0) //쿠키 최초 전달 후, response에 재전달하지 않기 위한 검증 
        	response.addCookie(cookie);

		return "menu/list";
	}

 

 

// 위의 list페이지에서 쿠키를 발급후, 상위페이지인 인덱스에서 쿠키를 찾아보았다

Cookie[] cookies = request.getCookies();
if (cookies != null) {
    for (Cookie cookie : cookies) {
        String name = cookie.getName();
        String value = cookie.getValue();
        System.out.println("Cookie Name: " + name);
        System.out.println("Cookie Value: " + value);
    }
} else {
    System.out.println("No cookies found in the request.");
}

👉 하위페이지(/menu/list) 에서 쿠키를 발급했을때, 상위페이지(/index)에서는 쿠키를 인식하지 못한다.

👉 list에 다시 재접속해보면 기존 쿠키가 인식되면서 값을 찾을 수 있다.

👉 반대로 index에서 쿠키가 발급되면 list에 접속해도 쿠키를 확인할 수 있다.

👉 세션은 상하페이지 상관없이 서블릿을 통해 공유된다. (session.setAttribute(), session.getAttribute());

 

 

 

 

 

 

 

✅ 세션과 쿠키 전체적으로 재정리 (아래 블로그 참고)

 

쿠키와 세션 개념

노션 페이지(아래 내용과 동일) 개요 쿠키와 세션은 개발자 말고도 인터넷 사용자라면 누구나 많이 들어본 단어입니다. 하지만 개념에 대해서는 많은 사람들이 헷갈려 하기에 쉽고 간단하게 정

interconnection.tistory.com

 

HTTP는 두가지 특징을 가진다 (connectionless, statelss) ▶ 응답을 하면 연결을 끊어버리는 특성. & 연결을 끊는 순간 클라이언트와 서버의 통신이 끝나며 상태정보는 유지하지 않는다 ▶ 이 연결을 유지하기 위해 세션과 쿠키를 사용한다 (인증유지)

 

세션 쿠키
서버에서 사용자 정보 파일을 관리함 (전용공간이 있음)
클라이언트 구분용으로 SID를 부여함
클라이언트가 웹브라우저 접속~종료까지 인증상태 유지
접속시간 제한 가능
클라이언트(브라우저)측에 저장되는 키&값 데이터파일
사용자 인증이 유효한 시간을 명시할 수 있음
인증시간 內  브라우저가 종료되어도 인증이 유지됨
서버 과부하 & 서버 메모리 부담이 올라감 서버 자원을 전혀 사용하지 않음
쿠키보다 보안에 좋다 (사용자 정보가 서버에 있으므로) 요청속도가 세션보다 빠르지만 스니핑당할우려가 있음
각 클라이언트에게 고유 ID를 부여
세션ID로 클라이언트를 구분해서 클라이언트에 맞는 서비스 제공
클라이언트의 상태정보를 로컬에 저장했다가 참조함
브라우저가 종료되어도 쿠키만료기간이 있다면 클라이언트에서 보관함
서버에서 쿠키를 읽어서 변경된 정보로 업데이트하여 응답 가능
세션 아이디도 쿠키를 사용해서 저장한다. (쿠키안에 SID만 심어두고 쿠키의 SID를 함께 서버에 전달해서 요청) 같은 요청을 할 경우, 사용자 요청 없이도 브라우저가 request할때 알아서 header에 넣어서 전송
로그인같이 보안상 중요한 작업 ex) 사이트에서 로그인시, 아이디와 비밀번호를 저장하시겠습니까?
쇼핑몰 장바구니 기능
자동로그인
팝업에서 '오늘 더이상 이 창을 보지 않음'
  • 세션은 url이달라져도 뽑아쓸 수 있다 (서블릿에서 뽑아쓸 수 있다)
  • url이 달라도 쿠키도 쓸 수 있다. 서버에 저장을 해놓느냐 그런거 없이 키만 가지고 다니느냐의 차이.
  • 쿠키가 더 많은 능력을 갖고 있음.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts