반응형

 

 

윈도우에서 리눅스를 사용할 때 윈도우 데스크탑으로 이동하는 명령어를 쉘 스크립트로 저장해서 사용

 

bash 실행 하면 동작하지 않는데,

새로운 쉘을 띄워서 사용하고 종료 후 원래의 쉘로 돌아와서, 경로를 이동하지 못한다고 한다.

 

source 실행 명령어를 사용하면

현재 쉘을 사용한다.

반응형

' > Linux' 카테고리의 다른 글

[goormide] goormide 웹 서버 설치  (0) 2022.08.09
리눅스 기초  (0) 2022.08.08
반응형

 

[ local 작업 ]
1. jar 파일 만들기
2. dockerfile 작성
3. docker 이미지 만들기
4. docker push

[ server 작업 ]
5. docker pull
6. docker run

 

 


 

 

1. jar 파일 만들기

 

Gradle bootJar로 jar 파일을 만든다.

 

build/libs 경로에 jar파일이 생성된다.

 

 

 



2. dockerfile 수정

 

FROM adoptopenjdk/openjdk11:alpine-slim

WORKDIR /chat

COPY build/libs/map-chat-v1.jar .

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "map-chat-v1.jar"]

 

도커 파일을 작성하여 이미지를 생성할 준비를 한다.

 

컨테이너 구동시 jar파일이 실행되도록 했다.

 

 

 

 



3. docker 이미지 만들기

 

docker build

-t 저장소명:태그

.

 

경로를 못찾는다고 할 경우

docker build

-f dockerfile경로

-t 저장소명/이미지명:태그

 

 

 



4. docker push

 

docker hub push가 간혹 안되는 경우가 있는데,

docker hub repository 이름과, push할 이미지 이름이 같아야 한다.

 

docker push 저장소명:태그

 

 

 


[ 여기서부터는 서버에서 작업 ]


5. docker pull

 

docker login -u 아이디

docker pull 저장소명:태그

 

 

 

 



6. docker run

 

docker run

-p 80:8080

저장소명:태그

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

반응형

' > docker' 카테고리의 다른 글

Docker 다시보기 정리  (1) 2023.10.18
[Docker] 도커 기초  (0) 2022.08.13
반응형

 

 

 


콜백함수, Promise, async-await

 

 - 비동기의 결과를 동기적으로 처리해주기 위해서 사용한다.


 

콜백 함수

다른 함수의 인자로 들어가서 나중에 실행되는 함수

 

함수내에서 A작업이 종료 후 B작업을 진행해야 할 경우 B작업을 콜백 함수라고 한다.

A작업이 끝난 후 B작업이 실행된다.

 

콜백 함수는 단순히 작업의 순서를 결정하는 것인데, 사실 이것은 함수를 사용하지 않고도 가능하다.

콜백 함수의 유용성은 비동기 작업을 할 때 나타난다.

 

 

 

A작업이 오래걸리는 작업(서버 통신)이면 비동기적으로 처리된다.

비동기로 처리되므로 아래 코드는 바로 수행되어, 비동기 처리 결과를 받는 곳에는 빈 값이 들어온다.

그래서 이를 방지하고자 비동기 처리가 완료되면, 처리 결과 값을 받은 이후에 실행되는 함수를 따로 둔다.

그 함수가 콜백 함수(비동기 처리가 완료되면 결과를 받아주는 함수)

 

 

 

사용법

function work(CallBack){

    A작업

    let B = CallBack(A작업의 결과)

}

 

work("A를 마치고", "B가 실행")

단순하게, A의 결과를 콜백 함수의 인자로 전달한다.

비동기 처리 이후 결과의 동기적 처리를 지원한다.

 


 

Promise

비동기 작업 이후 다음 작업을 연결시키는 기능을 가진 객체

성공(resolve) 또는 실패(reject)를 리턴한다.

then()내부에 resolve, catch()내부에 reject를 콜백 함수으로 작성하여 사용한다.

 

let promise = () => {  # 프로미스 객체는 작성하면 바로 execute 되기 때문에 함수안에 두는 것이 좋다.

 return new Promise((resolve, reject) => {  

      # 비동기 작업 진행         

         resolve(성공 결과 data)         

         reject(실패 결과 error)

   }

)};

 

promise().then((response) => { })   # 성공 시

promise().catch((error) => { })    # 실패 시

 

 

 

비동기 작업 체이닝(Promise 사용 이유)

then(resolve, reject)

Promise가 작업을 성공 하면 resolve() 실행, 실패하면 reject() 실행

then은 작업을 마치면 Promise를 리턴한다.

 

then()의 반환값

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

then 핸들러에서 값을 그대로 반환한 경우에는 Promise.resolve(<핸들러에서 반환한 값>)을 반환하는 것과 같다.

 

 

 

 

then 내부에 성공시 이어지는 동기 작업할 프로미스를 사용하여 체이닝을 한다.

let p1 = () => {
  return new Promise((resolve, reject)=>{
    let data = "p1 data "
    resolve(data);
  })
};

let p2 = (p1Value) => {
  return new Promise((resolve, reject) =>{
    let data = "p2 data "
    resolve(p1Value + data)
  })
};

p1()
  .then((res)=> p2(res))
  .then((res)=> console.log(res));

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

 

프로미스를 반환할 경우, 동등한 프로미스가 메서드 체인의 그 다음 then에 노출

 


 

async-await

async-await를 사용하면 훨씬 직관적이고 편하다.

내부적으로 Promise를 사용하기 때문에 Promise를 알고 있어야 한다.

 

 

async

함수앞에 async를 붙이면 Promise 객체로 사용할 수 있다.

함수를 호출하면 Promise 객체가 반환된다.

 

 

await 

반드시 async 함수 내부에서 사용해야 한다.

await은 Promise의 완료를 기다린다.

 

      사용법

      let result1 = await fetch("url", [ options ] )             

      let result2 = await promise(result1)

      # await의 뒤는 반드시 Promise 객체여야 한다.

 

await은 then()의 대체라고 보면 된다.

결과 값을 받으며 Promise의 체이닝같은 순차 로직을 명시적으로 작성할 수 있다.

 

 

에러처리

에러처리는 async 내부에서 try{  } catch{  } 로 처리한다.

async가 붙은 함수는 Promise 이므로 asyncFunction().catch((error) => { }) 로 처리해도 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

1계층 물리 계층

물리적인 매체를 이용해 비트 스트림을 전송

비트 단위 전송 010100

 

 


 

 

2계층 데이터링크 계층

hop to hop 전송 담당

Mac 주소 사용

유선 - 이더넷 MTU 1500byte

무선 - LTE

 

IP주소를 이용해 바로 옆(라우터, Host)으로 전달하는 역할을 하는 계층

 

데이터를 전송하고자 할 때 매체를 타고 전파된다.

매체를 이용하면 브로드캐스트로 전파된다. (사람이 공기를 이용해 말을 하듯이)

여러 노드가 동시에 매체를 이용하게되면, 충돌이 발생한다. 

 

충돌을 해결하기 위해 여러 시도 -> 정해진 시간마다 노드가 데이터를 보내는 방식

현재 사용하는 방식은 임의로 아무때나 Random Access하는 방식을 사용

임의로 아무때나 매체에 접근하므로 충돌은 언젠간 발생하며, 충돌을 해결해주어야 한다.

 

CSMA(carrier sense multiple access)

데이터를 보내기전에 매체를 감지하여 확인 후 전송한다.

 

CD(collision detection)

보낸 데이터의 충돌을 감지하면 전송을 멈춘다.

랜덤 딜레이를 주고 이후에 다시 전송을 시도한다.

 

 

 

스위치 (STAR형)

스위치가 중간에서 순서를 정리

스위치는 네트워크 관점에서 큰 의미 X

단순하게 연결을 위해 사용하는 것

switch table  [destination MAC : port]

 

 


 

ARP(IP를 사용하므로 사실 3계층에 위치)

IP를 이용해 MAC주소를 알아낸다.

 

프레임은 목적지 MAC주소로 데이터를 전송하므로 

목적지의 MAC주소를 알아야 한다.

MAC주소를 알아내기 위해 IP를 이용한다.

 

출발지 노드는 ARP TABLE [IP : MAC] 을 갖고 있다.

테이블에 IP에 해당되는 MAC 주소가 없다면

ARP TABLE을 채우기위해 브로드캐스트로 ARP를 전송

IP에 해당되는 정보를 가진 노드가 응답으로 자신의 MAC 주소준다.

출발지 노드는 목적지 MAC 주소를 채우고 데이터를 전송

 

스위치를 이용할 때는 데이터 링크(MAC)까지 올라가고,

ARP를 이용하려면 라우터 - 네트워크 계층 (IP)까지 올라가야 한다.

 

라우팅 테이블을 만들 때, ARP 테이블도 만든다.

 


 

 

3계층 네트워크 계층

장비: 라우터 - NAT, Forwarding, 방화벽

Host to Host

IP 주소 사용

 

 

라우터 동작 방식: 라우팅 알고리즘 -> 포워딩 테이블 구성 -> 포워딩

 

 

ip를 하나하나 다 저장하면 방대해지므로

서울, 대전, 부산과 같이 크게 묶은 후 라우팅 테이블의 ip range(Network Id)를 본다.

라우터는 라우팅 테이블을 보고 IP의 subnet mask 만큼 네트워크 IP로,

해당되는 라우터로 패킷을 forward (ip range가 가장 길게 매칭되는 곳으로 전송)

서브넷: 같은 prefix를 갖는 집합

 

 

 

라우팅 테이블 구성 방식

(1) Link state - 다익스트라 알고리즘

브로드캐스팅으로 자신의 링크정보를 네트워크에 뿌린다.

각 점은 각자 다익스트라 알고리즘을 수행하여 라우팅 테이블을 구성한다.

범위는 라우터들이 속한 도메인 범위에서 수행

 

(2) Distance vector - 벨만 포드 알고리즘

min(자신의 옆 라우터 이동 비용 + 도착지까지의 비용)

 

 

Fragmentation

IP 패킷을 2계층 이더넷 MTU에 맞게 분리, 조립하는 과정을 거친다.

재조립에 사용되는 식별자(identification), Offset을 헤더에 갖는다. (같은 데이터면 1씩 증가)

 

 

 


 

 

4계층 전송 계층

Process to Process

 

TCP, UDP

헤더에 포트번호를 갖고 있음

 

TCP, UDP 세그먼트도 이더넷 MTU를 따라야하기 때문에 분리한다.

 

 

 

TCP - 신뢰성 있는 통신

3way handshake(TCP Flags [Syn, Ack, Fin])

를 이용해 통신을 성립 후 신뢰성 지향 송수신을 한다.

버퍼를 이용해 흐름제어, 혼잡제어를 한다.

항상 수신측의 상황을 고려한다.

ack로 세그먼트의 시퀀스 넘버를 요청

 

흐름제어

슬라이딩 윈도우로 흐름을 제어한다.

ack를 받으면 ack 이후를 즉시전송 후 슬라이딩 윈도우를 밀고, 다시 전송한 세그먼트들의 ack를 기다린다.

윈도우의 크기는 수신측 상황에 맞춘다.

 

혼잡제어

송신한 세그먼트들이 timeout될 때 까지 지수적으로 증가시켜서 세그먼트를 전송해본다.

timeout이 발생하면 최종 전송 크기의 반으로 감소시켜 진행하고, 이후 가산 증가시키며 전송

 

 

 

 

 

UDP - 신뢰성 없는 통신

오류제어만 수행한다.

오류가 발생하면 해당 패킷은 폐기

헤더가 작아 커스텀하여 사용하기도 한다.

 


 

 

응용 계층

암호화, 실시간 처리 등을 응용계층에서 전담한다. (OSI 7 layer의 세션, 표현 계층의 역할을 포함한다.)

 

TCP socket 또는 UDP socket 을 형성하여 통신한다.

 

여러개의 소켓이 형성

소켓위에서 응용계층 프로세스가 동작한다.

전송계층의 헤더를 보고 맞는 소켓(port)으로 올린다.

 

 

 

 

HTTP 일 경우

헤더와 바디로 구성된 메세지를 전송계층에 데이터로 넘김

 

 

 

 


 

반응형

'CS > 네트워크' 카테고리의 다른 글

Blocking / Non Blocking, Synchronous / Asynchronous  (0) 2023.10.03
반응형

public class ChanningClass {
    public final String status;

    private ChanningClass(String status){
        this.status = status;
    }

    // BuildersImpl 인스턴스를 처음 생성할 메서드가 필요하다.
    public static Builders startMethod() {
        return new BuildersImpl();
    }
    
    // Builder 인터페이스
    interface Builders{
        Builders method1(String doSomething);
        Builders method2(String doSomething);
        ChanningClass build();
    }
    
    // Builder 구현체
    private static class BuildersImpl implements Builders{
        private String status;

        BuildersImpl(){
            this.status = "";
        }

        @Override
        public Builders method1(String doSomething) {
            this.status = this.status + doSomething;
            return this;
        }

        @Override
        public Builders method2(String doSomething) {
            this.status = this.status + doSomething;
            return this;
        }
        
        // 작성한 상태값을 인스턴스를 만들며 반환
        @Override
        public ChanningClass build() {
            return new ChanningClass(this.status);
        }
    }
}

 

메서드를 시작할 때 startMethod() 내부 인스턴스를 만들고,

 

인터페이스를 이용해 메서드 체이닝을 한다.

 

메서드가 오버라이딩 되어있다면 자식 메서드가 동작한다는 점을 이용하여 동작시킨다.

 

메서드가 종료할 때 build() 외부 인스턴스를 만들어 반환한다.

 

 

 

 

 

 


ChanningClass builders1 = ChanningClass.startMethod().method1("aaaa").method2("bbbb").build();
ChanningClass builders2 = ChanningClass.startMethod().method2("bbbb").method1("aaaa").build();

System.out.println(builders1.status);
System.out.println(builders2.status);

 

 

 


@Builder

 

public static Book.BookBuilder builder() {
   return new Book.BookBuilder();
}

 

public static class BookBuilder {
   private Long id;
   private String BookName;
   private Publisher publisher;
   private List<BookLoan> loanBookList;
   private List<BookReservation> bookReservationList;

   BookBuilder() {
   }

   public Book.BookBuilder id(final Long id) {
      this.id = id;
      return this;
   }

   public Book.BookBuilder BookName(final String BookName) {
      this.BookName = BookName;
      return this;
   }

   public Book.BookBuilder publisher(final Publisher publisher) {
      this.publisher = publisher;
      return this;
   }

   @JsonIgnore
   public Book.BookBuilder loanBookList(final List<BookLoan> loanBookList) {
      this.loanBookList = loanBookList;
      return this;
   }

   @JsonIgnore
   public Book.BookBuilder bookReservationList(final List<BookReservation> bookReservationList) {
      this.bookReservationList = bookReservationList;
      return this;
   }

   public Book build() {
      return new Book(this.id, this.BookName, this.publisher, this.loanBookList, this.bookReservationList);
   }

 

@Builder는 굳이 인터페이스까진 만들지 않는다.

 

내부 인스턴스를 만드는 builder(), 외부 인스턴스를 만드는 build() 

 

시작과 끝 메서드의 사용 방식은 같다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

반응형
반응형

 


REST(Represetational State Transfer)

기술이 아닌 약속이다.

요청에 대한 JSON 또는 XML형식으로 자원의 상태 응답

자원(데이터)의 상태를 주고 받는 것

 

 

특징

Client, Server 구조 / 클라이언트는 요청하고, 서버는 응답하는 구조

Stateless / 서버에서는 클라이언트의 상태 값을 저장하지 않는다. (인증, 인가에 JWT 사용)

 

HTTP 프로토콜을 이용해서 JSON 데이터를 응답으로 주기 때문에 어플리케이션의 통합과 분리가 용이하다.

 

 

규약

자원의 식별 - URL로 자원을 구분, 식별

메세지를 통한 리소스 조작 - HTTP header에 자원의 타입을 명시, 데이터 일부를 메세지로 전달

자기 서술적 메세지 - 요청하는 데이터가 HTTP methods 중 무엇인지, 필요한 정보를 포함하여 전달

어플리케이션 - 데이터뿐만 아니라 추가 정보도 제공

 

 

URI 설계 패턴

URI - 특정 자원에 대한 URI주소로 접근. 변경될 수 있다.

URL - 특정 자원에 대한 위치. 변경될 수 없다.

 

슬래시로 계층을 구분

하이픈을 사용한다.

소문자가 적합

컬렉션은 복수형을 사용

 

CRUD 명시 하지 않는다.

파일형식, 경로를 명시하지 않는다.

 

 

HTTP Methods

클라이언트가 요청을하고 서버의 응답을 기다린다.

 

GET

자원의 취득

데이터 기준: 안정성 o, 멱등성 o (데이터가 변하지 않는다.)

body를 사용하지 않는다.

 

POST

자원의 생성

데이터 기준: 안전성 x, 멱등성 x (매번 데이터가 생성)

body를 사용한다.

 

PUT

자원의 수정

데이터 기준: 안전성 x, 멱등성 o (한번 수정되고 같은 결과)

body를 사용한다.

 

DELETE

자원의 삭제

데이터 기준: 안전성 x, 멱등성 o (한번 삭제되고 같은 결과)

body를 사용하지 않는다.

 

 

HTTP Status Code

100 - 처리가 계속 되고 있는 상태

200 - 성공

300 - 리다이렉션

400 - 클라이언트 에러

500 - 서버 에러

 

 

 


Java  -- Json

 

 

object-> String(json형태)

ObjectMapper writeValueAsString()

 

 

String(json형태) -> object

ObjectMapper readValue()

 

 

String(json형태) -> json

ObjectMapper readTree()

 

 

JsonNode  값을 변경할 수 없다.ObjectNode  값을 변경할 수 있다.

 

 


 

Jackson

package com.example.jacksontest.dto;

import lombok.*;

import java.util.List;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private List<Item> items;

    @Getter
    @Setter
    @NoArgsConstructor
    @ToString
    @AllArgsConstructor
    public static class Item{
        private String itemName;
        private int count;

    }

}

 

 

 

{
  "id" : 1,
  "name" : "cha",
  "items" : [
    {
      "itemName" : "coin",
      "count" : 3
    },{
      "itemName" : "Phone",
      "count" : 1
    },{
      "itemName" : "cigarette",
      "count" : 5
    }
  ]

}

 

 

 

ObjectMapper objectMapper = new ObjectMapper();
// 읽기
User user = objectMapper.readValue(new File("src/main/resources/data.json"), User.class);
System.out.println(user);

// 쓰기
File f = new File("src/main/resources/data1.json");
objectMapper.writeValue(f, user);

// Json -> String 으로 변환
String s = objectMapper.writeValueAsString(user);

// String -> ObjectNode 로 변환
ObjectNode objectNode = (ObjectNode) objectMapper.readTree(s);
System.out.println(objectNode.toPrettyString());

// Json -> Java Pojo
JsonNode list = objectNode.get("items");
User user1 = objectMapper.readValue(s, new TypeReference<User>() {});
System.out.println(user1);

// key 를 이용해 하나씩 접근
System.out.println("key 로 접근: " + objectNode.get("name"));
System.out.println("Array 일 경우: " + objectNode.get("items"));

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

XSS(Cross-Site Scripting)

(사용자가 사이트를 신뢰한다는 점을 이용)

스크립트 삽입 공격 방식

 

JS 스크립트는 어느위치에 있던 동작하기 때문에 공격자가 스크립트 코드가 포함된 게시글을 작성하여 등록

일반 사용자가 해당 글을 클릭하면 script가 동작하여 이루어지는 공격 방식

 

무조건 Secure Coding을 해줘야 한다. 

 

 

대응

 - Secure coding

<, >, = 과 같은 입력값에 공격에 사용될만한 문자가 있다면 치환하여 사용, DB에 저장한다.

Sql Injection도 비슷한 방식으로 대응할 수 있다.

 

 - HttpOnly

Secure coding이 적용되어 있지 않아 스크립트가 동작

쿠키 탈취 시도 시 쿠키가 HttpOnly 설정이 되어있다면 js로 쿠키를 읽어낼 수 없다.

 

 


 

CSRF (Cross Site Request Forgery)

(사이트가 사용자를 신뢰한다는 점을 이용, 신뢰할만한 쿠키와 토큰을 브라우저에서 갖고 있다는 점)

피싱 사이트를 만들어, 피싱 사이트에 사용자가 접근하면

스크립트를 이용해 특정 사이트로 요청을 보내, 사용자나 관리자의 권한으로 서버에 write 하도록 유도하는 공격

피싱 사이트에서 요청을 위조해서 Request Forgery

 

기본적으로 브라우저의 SOP 정책으로 응답된 데이터에 접근이 불가능하다. (공격자가 해당 정보를 이용할 수 없다)

하지만, 응답된 데이터 접근 불가능할뿐이지 서버에 write는 가능하다. (공격자가 원하는 대로 정보를 수정)

그래서 write를 방지하고자 Preflight 또는 CSRF token을 도입하게 되었다.

 

 

대응

 - Preflight

(1) 예비 요청을 Option 메서드로 보내서, 서버의 Access-Control-Allow-Origin 을 확인한다.

서버에서 허가된 Access-Control-Allow-Origin 목록을 응답으로 보내준다.

 

(2-1) 허가된 주소에 해당되면 정식 요청을 보내고, 응답을 사용한다.

(2-2) 허가된 Origin이 아니라면 예비 요청에서 막혔음을 확인했기 때문에 정식 요청을 보내지 않는다.

get, head, post 가 아닌 서버 데이터를 변형시키는 put, patch, delete면 Prefilght를 보내게 된다.

 

 - CSRF Token

CSRF토큰 난수를 두면 요청시에 모든 요청은 CSRF토큰 난수를 보내야 인가를 받는다.

서버에서 CSRF Token 난수가 맞는지 확인한다. 서버에서 만든 페이지에서 요청한 것이 맞으므로 수행

위조된 요청은 CSRF Token가 없으므로 write가 동작하지 않는다.

 

 

 


브라우저의 보안 SOP

SOP(Same Origin Policy)

브라우저가 적용한 보안 방식

요청한 Origin과 응답한 Origin이 Same Origin이어야 자원 접근이 가능하다.

script뿐만 아니라, document도 출신(Origin)이 다르면 서로 접근이 불가능하다.

 

 

XSS는 Secure Coding으로 막았다고 가정, CSRF 공격 시

해킹1. (document로 정보 가져오기)

요청한 위조 사이트와 정보를 가져온 사이트의 Origin이 다르기 때문에,

유저 인증을 이용해 document를 가져오는 건 성공해도 document를 읽어낼 수 없다.

결과적으로 해커의 서버에 전송된 document에는 아무것도 없다

 

해킹2. (script로 정보 가져오기)

요청하는 해커의 서버와 응답 사이트의 Origin이 다르기 때문에 요청이 무시되어 동작하지 않는다.

 

 

 

CORS(Cross Origin Resource Sharing)

SOP 보안 정책을 일부 허가된 Origin은 해제

script, document로 다른 Origin 서버에 요청해서 받은 자원을 접근할 수 있게 한다.

 

서버 Access-Control-Allow-Origin 에 요청하는 Origin을 추가한다.

 

 

 


 

HTTPS 

네트워크상에서 정보가 탈취되지 않도록 방지한다.

RSA 암호화를 사용하는 것. 서버가 비밀키를 갖고 있다.

공개키로 암호화해서 데이터를 보내고 전달받은 데이터를 서버가 자신의 비밀키로 푼다.

RSA 암호화는 컴퓨터에게 부담을 주기 때문에 이후부터는 대칭키를 교환하여 사용한다.

 

RSA

두 소수를 곱하여 큰 수를 만들어낸다. (두 소수도 자체도 크다.)

두 소수로 큰 수를 구하는 것은 쉽지만

반대로, 큰 수에서 두 소수를 구하는 것은 어렵다는 특징

반응형
반응형

 


 

 

 

전체적인 인증 흐름

Filter(username, password 토큰 생성) ->  Manager(Provider 구분) ->  Provider(실제 인증 처리부) ->

 

Service(username으로 DB에서 조회) ->  Details(User정보 구성) ->

 

Provider(입력 token과 Details 비교 검증, 일치할 시 Authentication 리턴) -> 

 

Filter(SpringContext에 Authentication 등록)

 

 

간단 요약

(입력된 username, password 토큰)을

(username으로 DB에서 조회한 유저정보)랑 비교 검증

일치하면 (Authentication 권한과 정보)를 SecurityContext에 등록

스택을 쌓아가며 인증처리를 한다.

 


 

AuthenticationFilter

인증의 처음과 마지막을 제어

 

처음

form 값으로 UsernamePassworAuthenticationToken을 만든다.

 

마지막

Security Session(Context)에 인터페이스 Authentication를 넣는다.

구현체 UsernamePassworAuthenticationToken는두개의 생성자를 갖고 있다. (인증 전, 인증 후)

 

 


 

전체 로직 처리는 AuthenticationManager에서 한다.

 

Provider 종류에 알맞게 인증 처리하는 곳 (Factory)

실제 인증은 AuthenticationProvider에서 처리

for (AuthenticationProvider provider : getProviders()) {
   if (!provider.supports(toTest)) {
      continue;
   }
   if (logger.isTraceEnabled()) {
      logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
            provider.getClass().getSimpleName(), ++currentPosition, size));
   }
   try {
      result = provider.authenticate(authentication);
      if (result != null) {
         copyDetails(authentication, result);
         break;
      }
   }

등록된 provider를 반복문으로 돌려 해당되는 provider를 찾는다.

Token(Username, password)DB정보(UserDetail)와 검증해서 authenticate를 통과하나 확인한다.

토큰과 userDetail이 일치하는 인증된 사용자이므로 break로 반복문 종료.

 

 

if (result != null) {
   if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
      // Authentication is complete. Remove credentials and other secret data
      // from authentication
      ((CredentialsContainer) result).eraseCredentials();
   }
   // If the parent AuthenticationManager was attempted and successful then it
   // will publish an AuthenticationSuccessEvent
   // This check prevents a duplicate AuthenticationSuccessEvent if the parent
   // AuthenticationManager already published it
   if (parentResult == null) {
      this.eventPublisher.publishAuthenticationSuccess(result);
   }

   return result;
}

인증되면 Authenticaton 객체를 AuthenticationFilter에게 return

 


 

실질적인 인증 처리는 AuthenticationProvider에서 한다.

 

인증 전 Authentication 객체를 받아서 인증 후 객체로 만드는 곳

Provider는 여러개일 수 있다.

해당되는 Provider로 인증을 진행한다.

 

    UserDetailService (Login 요청이 오면 loadUserByUserName 메서드 동작), 인터페이스이므로 구현

    Username으로만 Repository를 이용해 DB에 조회한다.

    유저가 있다면 UserDetails로 반환한다.

@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
   final UserRepository userRepository;

   @Override
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      Optional<User> optionalUser = userRepository.findByUsername(username);
      if(optionalUser.isPresent()){
         return new PrincipalDetail(optionalUser.get()); 
      }else{
         return null;
      }
   }
}

 

 

 

    UserDetails, 인터페이스이므로 구현해서 유저의 정보를 제공 (UserDetailService에서 생성된다.)

    사용자의 정보 제공 목적으로 사용된다. (DB데이터, 로그인된 유저 Session)

    유저명, 비밀번호, 유저 권한 등을 갖고 있다.

    생성자에 User를 넣어준다.

public class PrincipalDetail implements UserDetails {
   private User user;

   public PrincipalDetail(User user){
      this.user = user;
   }

   @Override
   public Collection<? extends GrantedAuthority> getAuthorities() {
      Collection<GrantedAuthority> collect = new ArrayList<>();
      collect.add(new GrantedAuthority() {
         @Override
         public String getAuthority() {
            return user.getRole().name();
         }
      });

      return collect;
   }

   @Override
   public String getPassword() {
      return user.getPassword();
   }

   @Override
   public String getUsername() {
      return user.getUsername();
   }

   @Override
   public boolean isAccountNonExpired() {
      return true;
   }

   @Override
   public boolean isAccountNonLocked() {
      return true;
   }

   @Override
   public boolean isCredentialsNonExpired() {
      return true;
   }

   @Override
   public boolean isEnabled() {
      return true;
   }
}

 

 

 

UserDetails 객체는 UsernamePasswordAuthenticationToken(Authentication)을 생성, 보관한다.

 

AuthenticationProvider에서

전달받은 UserDetails와 UsernamePassworAuthenticationToken(Authentication) 을 검증하여 인증처리

암호가 같다면 인증처리된 Authentication을 AuthenticationManager에게 반환

(이전에 password를 해시암호화 해야한다.)

 

AuthenticationManager에서 AuthenticationFilter에게 반환

Authentication를 SecurityContext에 저장

 

 


 

 

@Configuration
@EnableWebSecurity
public class SecurityConfig {

   @Bean
   public BCryptPasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
   }

   @Bean // 필터를 bean component 생성
   public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {  // 원하는 필터를 골라서 커스텀 적용시킬 수 있다.
      return http
              // 권한 설정
              .csrf().disable() // 해당 설정 안하면 csrf 토큰이 없어서, post 는 forbidden 이 나오므로 테스트에선 해제
              .authorizeRequests()
              .antMatchers("/user/**").hasRole("USER") // ROLE 이 필요한 URL 을 먼저 적용 시킨다.
              .antMatchers("/manager/**").hasRole("MANAGER")
              .antMatchers("/login").not().hasAnyRole("USER", "MANAGER") // 로그인 이후 접근 금지
              .antMatchers("/**").permitAll()

              // 로그인
              .and()
              .formLogin() // 해당 url 은 form 으로 이동
              .loginPage("/login")
              .loginProcessingUrl("/login") // 시큐리티가 로그인 대신 진행
              .defaultSuccessUrl("/")
              .failureUrl("/login")

              // 로그아웃
              .and()
              .logout()
              .logoutSuccessUrl("/")
              .deleteCookies("JSESSIONID")

              .and().build();

   }
}

 

 

 


 

https://mangkyu.tistory.com/76

반응형

'프로그래밍 > Security' 카테고리의 다른 글

웹 요청 정리  (0) 2022.10.20
[쿠키] Javascript로 쿠키에 직접 접근, HttpOnly, CORS  (0) 2022.10.19
[Web 보안] XSS, CSRF  (0) 2022.08.25
[인증과 인가] 쿠키와 세션, JWT  (0) 2022.06.23
반응형

 

쓰기와 쓰기가 동시에 작업하는 것이 불가능

읽기와 읽기는 동시에 언제든 가능

 

문제 부분은 쓰기 트랜잭션읽기 트랜잭션이 동시에 일어날 때

 

하나의 트랜잭션은 발생 시점부터 데이터 일관성을 가져야 한다.

 

 

 

Read uncommited - 오손 읽기(Dirty read) 

commit되지않은 데이터를 읽는 문제

 

 

Read commited - 반복 불가능 읽기(Non repeatable read)

update -> commit된 데이터를 읽어, 데이터 일관성이 깨진다.

 

 

Repeatable read - 유령 데이터 읽기(Phantom read)

트랜잭션 시작 전 commit 된 데이터만 undo영역을 이용하여 읽는다. 일관성이 깨지지 않는다.

insert -> commit 된 데이터를 읽어, 데이터를 추가로 읽어 데이터 일관성이 깨진다.

 

 

Serializable - 모든 문제 해결

트랜잭션이 다른 트랜잭션으로 부터 완전히 독립

 

 

 

 

MySQL은 Repeatable read를 사용하므로 유령 데이터 읽기가 발생할 수 있지만,

inno db 넥스트 키락으로 row에 락을걸어 insert 트랜잭션을 막기때문에, 유령 데이터 읽기가 발생하지 않는다.

 


 

https://idea-sketch.tistory.com/46

 

[MySQL]MySQL 벼락치기(5) - 갭락(Gap Lock)과 넥스트 키 락(Next-Key Lock)

이번 포스팅은 사내에서 MySQL 관련 내용 발표를 위해 Real MySQL(http://wikibook.co.kr/real-mysql/) 서적을 기반으로 학습하고 이해한 내용을 정리하는 포스팅이다. 포스팅에서는 주로 InnoDB 스토리지 엔진

idea-sketch.tistory.com

 

반응형
반응형

 


 

JPA 테스트 중에 분명 fetch LAZY로 설정했는데, 

 

sql을 보니 LAZY Entity까지 조인을 하면서 마치 EAGER처럼 동작을 하는 문제가 있었다.

 

 


 

 

@OneToMany(mappedBy = "user1", fetch = FetchType.LAZY)
private List<UserParty> userParty;

 

@Test
void test9(){
    itemRepository.findByItemNameLikeAndUser1_NameLike("%2", "c%").forEach(System.out::println);
    System.out.println("-----");
    // lazy 인데 왜 userParty 쿼리가 나갈까

}

 

itemRepository에서 user1을 사용하는 쿼리 메서드

 

User1 ---> UserParty는 분명 LAZY인데 마치 EAGER처럼 UserParty를 전부 가져왔다.

 

 

문제 상황은 [ Item ---> User1 ---> UserParty ] 까지 전이되어 전부가져옴

 

원하는 것은 [ Item ---> User1 ] 까지

 


 

해결은 단순했다.

 

@OneToMany(mappedBy = "user1", fetch = FetchType.LAZY)
@ToString.Exclude
private List<UserParty> userParty;

 

Entity 상단에 설정된 @ToString 때문에 getter가 동작하여 EAGER처럼 계속 조회해서 사용하는 것이었다.

 

@ToString.Exclude를 붙여서 getter를 호출하지 않게 설정하고 LAZY로 정상 작동되게 했다.

 

fetch LAZY 를 설정하면 ToString.Exclude 를 같이 사용

반응형

+ Recent posts