AOP (Aspect Oriented Programming)란?

  • AOP, 관점 지향 프로그래밍은 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법을 말한다.
  • 관점 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 본다는 말이고 따라서 관점을 기준으로 각각 모듈화하는 프로그래밍 기법
    • '핵심기능': 각 API 별 수행해야 할 비즈니스 로직 ex) 상품 키워드 검색, 관심상품 등록, 회원 가입, 관심상품에 폴더 추가, ....
    • '부가기능': 핵심기능을 보조하는 기능 ex) 데이터베이스 연결, 파일 입출력, 회원 패턴 분석을 위한 로그 기록, API 수행시간 저장 등
    • *모듈화 : 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것 
  • OOP(Object-oriented Programming, 객체 지향 프로그래밍)과 나란히 하는, 서로 보완관계에 있는 기술이다.

 

 

[그림 1] AOP 예시

 

 

[그림 1]과 같이 클래스 A, B, C에서 공통적으로 나타나는 색깔 블록은 중복되는 메서드, 필드, 코드 등이다. 이때 예를 들어 클래스 A의 주황색 블록 부분을 수정해야 한다면 클래스 B, C의 주황색 부분도 일일이 찾아 수정해야 한다. 이는 SOLID원칙을 위배하며 유지보수를 어렵게 만든다. 이런 식으로 소스 코드상에서 계속 반복해서 사용되는 부분들을 흩어진 관심사(Crosscutting Concerns)라고 한다.  

 

결국 AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 흩어진 관심사를 모듈화하겠다는 의미다. [그림 1]과 같이 주황색, 파란색, 빨간색 블록처럼 모듈화 시켜놓고 어디에 적용시킬지만 정의해주면 되는 것이다. 이때 모듈화 시켜놓은 블럭을 Aspect라고 한다. 

 

AOP 관련 용어

  • Aspect : 흩어진 관심사를 모듈화 한 것. 
  • Target : Aspect를 적용하는 곳. 클래스, 메서드 등..
  • Advice : 실질적으로 어떤 일을 해야 할 지에 대한 것, 실질적인 부가기능을 담은 구현체
  • Join Point : Advice가 적용될 위치 혹은 끼어들 수 있는 시점. 메서드 진입 시점, 생성자 호줄 시점, 필드에서 꺼내올 시점 등 끼어들 시점을 의미. 참고로 스프링에서 Join Point는 언제나 메서드 실행 시점을 의미 한다.
  • Point Cut : Join Point의 상세한 스펙을 정의한 것. "A란 메서드의 진입 시점에 호출할 것"처럼 구체적으로 Advice가 실행될 시점을 정함.

 

AOP 적용 방법

  • 컴파일 타임 적용 : 컴파일 시점에 바이트 코드를 조작하여 AOP가 적용된 바이트 코드를 생성하는 방법.
  • 로드 타임 적용 : 순수하게 컴파일한 뒤, 클래스를 로딩하는 시점에 클래스 정보를 변경하는 방법
  • 런타임 적용 : 스프링 AOP가 주로 사용하는 방법. A라는 클래스 타입의 Bean을 만들 때 A 타입의 Proxy Bean을 만들어 Proxy Bean이 Aspect 코드를 추가하여 동작하는 방법.

 

스프링 AOP

  • 스프링에서 제공하는 스프링 AOP는 프록시 기반의 AOP 구현체이다.
  • 프록시 객체를 사용하는 것은 접근 제어 및 부가 기능을 추가하기 위해서이다.
  • 스프링 AOP는 스프링 Bean에만 적용할 수 있다.
  • 모든 AOP 기능을 제공하는 것이 목적이 아닌, 중복 코드, 프록시 클래스 작성의 번거로움 등 흔한 문제를 해결하기 위한 솔루션을 제공하는 것이 목적이다.
  • 스프링 AOP는 순수 자바로 구현되었기 때문에 특별한 컴파일 과정이 필요하지 않다.

 

*프록시 패턴

 

[그림 2] Proxy 패턴

 

프록시 패턴에서는 interface가 존재하고 Client는 이 interface 타입으로 Proxy 객체를 사용한다. Proxy 객체는 기존의 타겟 객체(Real Subject)를 참조한다. Proxy 객체와 기존의 타겟 객체의 타입은 같고, Proxy는 원래 할 일을 가지고 있는 Real Subject를 감싸서 Client의 요청을 처리한다.

 

왜? 이렇게 해서 패턴을 사용하는 걸까?
그 이유는 기존 코드의 변경 없이 접근 제어 또는 부가 기능 추가를 위해서다.

 

스프링 AOP 구현

gradle - Spring AOP를 사용하기 위해서는 아래와 같이 의존성을 추가해줘야 한다.

implementation 'org.springframework.boot:spring-boot-starter-aop'

 

 

 

// Aspect 정의
@Component
@Aspect
public class PerfAspect {

  // 빈이 가지고있는 모든 퍼블릭 메쏘드
  @Around("bean(simpleServiceEvent)")
  public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed();
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}

위와 같이 @Around 어노테이션에 bean(simpleServcieEvent)처럼 적용될 빈을 명시할 수 있다. 그럼 해당 빈이 가지고 있는 모든 public 메서드에 해당 기능이 적용된다.

 

 

@Around 외에 타겟 메서드의 Aspect 실행 시점을 지정할 수 있는 어노테이션은 다음과 같은 것들이 있다.

 

  • @Before : Advice 타겟 메서드가 호출되기 전에 Advice 기능 수행
  • @After : 타겟 메서드의 결과에 관계없이 타겟 메서드과 완료되면 Advice 기능 수행
  • @AfterRunning : 타겟 메서드가 성공적으로 결과값을 반환 한 후에 Advice 기능 수행
  • @AfterThrowing : 타겟 메서드가 수행 중 예외를 던지면 Advice 기능 수행
  • @Around : Advice가 타겟 메서드를 감싸 타겟 메서드 호출 전, 후에 Advice 기능 수행

 

정리 :

AOP는 흩어진 관심사(Crosscutting Concerns)를 모듈화 할 수 있는 프로그래밍 기법이다

부가적인 기능에 대한 관심사를 분리해서 따로 공통적인 처리를 하도록 해 효율적으로 코드를 작성, 유지보수 하는 방법

 


참고

1. https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop

2. https://engkimbs.tistory.com/746

3. https://www.inflearn.com/course/spring-framework_core

4. https://yadon079.github.io/2021/spring/spring-aop-core

5. https://code-lab1.tistory.com/193

'Coding > Spring' 카테고리의 다른 글

[30] Spring 심화주차 키워드정리  (0) 2022.12.18
[28] Transaction  (0) 2022.12.14
[26] OAuth / 소셜 로그인  (0) 2022.12.14
[25] JPA 다양한 연관관계 매핑  (0) 2022.12.13
[24] ERD(Entity Relationship Diagram)  (0) 2022.12.13

OAuth(Open Standard for Authorization)

  • 개방형 Authorization 의 표준이며 API 허가(Authorize)를 목적으로 JSON 형식으로 개발된 HTTP 기반의 보안 프로토콜
  • 사용자들이 사용하고자 하는 웹사이트 및 애플리케이션에 비밀번호를 제공하지 않고 접근 권한을 부여 받을 수 있게 해주는 공통적 수단으로서 사용 되어지는 기술
  • 다양한 클라이언트 환경에 적합한 인증(Authentication) 및 인가(Authorization) 의 위임 방법을 제공하고 그 결과로 클라이언트에게 접근 토큰 (Access Token) 을 발급하는 것에 대한 구조

 

https://en.wikipedia.org/wiki/OAuth

 

OAuth - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Open standard for authorization For MediaWiki's (the software used by Wikipedia) OAuth support, see mw:Help:OAuth OAuth (short for "Open Authorization"[1][2]) is an open standard for a

en.wikipedia.org

 

2. 소셜 로그인

  • 모든 웹 사이트에서 회원가입 과정을 거치는 것은 사용자에게 부담이 된다.
  • 매번 번거로운 회원가입 과정을 수행해야 할 뿐 아니라, 웹 사이트마다 다른 아이디와 비밀번호를 기억해야 합니다. 또한 웹 사이트를 운영하는 측에서도 회원들의 개인정보를 지켜야하는 역할이 부담이 된다.
  • 바이러스와 백신의 관계 처럼, 발전하는 해킹 기술을 막기 위해 보안을 강화하는 노력이 지속적으로 필요하기 때문
  • 이런 문제를 해결하기 위해 OAuth 를 사용한 소셜 로그인이 등장했다.

 

① 카카오 로그인 흐름 이해하기

 

 

② 카카오 로그인 애플리케이션 등록하기

https://developers.kakao.com/console/app

  1. 위 사이트에 접속한다.
  2. 회원가입
  3. 내 애플리케이션 메뉴 선택 > 애플리케이션 추가하기
    1. 앱 아이콘, 앱 이름, 사업자명 저장
    2. 사이트 도메인 등록하기
    3. 카카오로 로그인 했을 때 인가토큰을 받게 될 Redirect URI (callback) 를 설정하기 ( http://localhost:8080/api/user/kakao/callback)

 

③ 카카오 서버에서 인가코드 받기

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 


자세한 사용법은 아래 노션 자료 참고하기!

https://www.notion.so/Project-MySelectShop-OAuth2-1-6cca9ab6f31a4d29968fd01590e74a36

 

'Coding > Spring' 카테고리의 다른 글

[28] Transaction  (0) 2022.12.14
[27] Spring AOP  (0) 2022.12.14
[25] JPA 다양한 연관관계 매핑  (0) 2022.12.13
[24] ERD(Entity Relationship Diagram)  (0) 2022.12.13
[23] Spring Security  (0) 2022.12.13

엔티티의 연관관계를 매핑할 때는 3가지를 고려해야한다.

  1. 다중성 : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)
  2. 단방향, 양방향 :  (객체 참조)
  3. 연관관계의 주인 : 양방향일 때, 연관 관계에서 관리 주체

연관관계 매핑 : 비즈니스 로직, 비즈니스 요구사항에 따라 개발자가 더 적절한 관계 설정 방법을 선택

 


다중성

다대일(@ManyToOne)

일대다(@OneToMany)

일대일(@OneToOne)

다대다(@ManyToMany)

 

※ 보통 다대일과 일대다 관계를 많이 사용하고 다대다 관계는 실무에서 거의 사용하지 않는다.

 

단방향, 양방향

  • 데이터베이스 테이블은 외래 키 하나로 양 쪽 테이블 조인이 가능하다.
  • 데이터베이스는 양방향으로 쿼리가 가능하기 때문에 단방향이니 양방향이니 나눌 필요가 없다.
  • 반면, 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능하다.
  • 그렇기 때문에 두 객체 사이에 하나의 객체만 참조용 필드를 갖고 참조하면 단방향 관계, 두 객체 모두가 각각 참조용 필드를 갖고 참조하면 양방향 관계라고 한다.
  • 사실, 엄밀하게는 양방향 관계↔️는 없고 두 객체가 단방향 참조를 각각 가져서 양방향 관계처럼 사용하고 말하는 것

 

연관관계 주인

  • 두 객체(A, B)가 양방향 관계, 다시 말해 단방향 관계 2개(A→B, B→A)를 맺을 때, 양방향 참조가 존재하기 때문에 어느 쪽에서 외래키를 관리할지 정해야한다.
  • 외래 키를 가진 테이블을 매핑한 엔티티에서 외래 키를 관리하는게 효율적이다.
  • 따라서 이곳을 연관관계의 주인으로 선택한다. 외래 키를 가진 엔티티가 주인이라고 생각하면 쉽다. 
  • 일대다, 다대일 관계에서 항상 '다'쪽이 외래키를 가진다. 주인이 아닌 쪽은 외래 키를 변경할 수 없고 읽기만 가능하다.  

 


다대일(N : 1) 단방향

게시판(Board)과 게시글(Post)의 관계로 이해해 보기! 

  • 요구 사항
    • 하나의 게시판(1)에는 여러 게시글(N)을 작성할 수 있습니다.
    • 하나의 게시글은 하나의 게시판에만 작성할 수 있다.
    • 게시글과 게시판은 다대일 관계를 갖습니다.

데이터베이스를 기준으로 다중성(게시글N : 게시판1)을 결정했다. 즉, 외래 키를 게시글(N)이 관리하는 일반적인 형태.

다대일 단방향에서는 다 쪽인 Post에서 @ManyToOne 만 추가해준 것을 확인할 수 있다. 반대로 Board에서는 참조하지 않는다. (단방향이기 때문)

@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;
    //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;
    //... getter, setter

 

다대일(N : 1) 양방향

다대일 양방향으로 만드려면 일(1) 쪽에 @OneToMany 를 추가하고 양방향 매핑을 사용했으니 연관 관계의 주인을 mappedBy 로 지정해준다. mappedBy로 지정할 때 값은 대상이 되는 변수명을 따라 지정하면 된다. 여기서는 Post 객체(대상)의 board라는 이름의 변수이기 때문에 board로 지정

@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;
    //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @OneToMany(mappedBy = "board")
    List<Post> posts = new ArrayList<>();
    //... getter, setter
}

 

일대다(1 : N) 단방향  

(참고로 실무에서는 일대다(1:N) 단방향은 거의 쓰지 않는다.)

데이터베이스 입장에서는 무조건 다(N)쪽에서 외래키를 관리한다. 일(1)쪽 객체에서 다(N) 쪽 객체를 조작(생성,수정,삭제)하는 방법!

@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;
  //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @OneToMany
    @JoinColumn(name = "POST_ID") //일대다 단방향을 @JoinColumn필수
    List<Post> posts = new ArrayList<>();
    //... getter, setter
}

@OneToMany에 mappedBy가 없어진다. 양방향이 아니기 때문. 대신 @JoinColumn을 이용해서 조인을 한다.

실제 사용은 아래와 같다.

//...
Post post = new Post();
post.setTitle("가입인사");

entityManager.persist(post); // post 저장

Board board = new Board();
board.setTitle("자유게시판");
board.getPosts().add(post);

entityManager.persist(board); // board 저장
//...

위와 같은 시나리오로 동작을 살펴보면, post를 저장할 때는 멀쩡하게 insert 쿼리가 나가지만 그 다음이 문제이다.

board를 저장할 때는 Board를 insert하는 쿼리가 나간 후에 post를 update하는 쿼리가 나간다.

왜냐하면 board.getPosts().add(post); 부분 때문!

Board 엔티티는 Board 테이블에 매핑되기 때문에 Board 테이블에 직접 지정할 수 있으나, Post 테이블의 FK(BOARD_ID)를 저장할 방법이 없기 때문에 조인 및 업데이트 쿼리를 날려야 하는 문제가 있다.

 

치명적인 단점

  • 일만 수정한 것 같은데 다른 수정이 생겨 쿼리가 발생하는 것.
    • Board를 저장했는데 왜 Post가 수정이 되지? 이런 생각을 하게 만듦.
    • 업데이트 쿼리 때문에 성능상 이슈는 그렇게 크지는 않음.

 

정리 : 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자. 엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리한다는 것은 성능 문제도 있지만 관리도 부담스럽다. 해결법은 다대일 양방향 매핑을 사용하는 것이다. 

 

일대다(1 : N) 양방향

(실무 사용 금지 )

일대다 양방향 매핑은 존재하지 않는다. 대신 다대일 양방향 매핑을 사용해야한다. (다대일 양방향과 일대다 양방향은 사실 똑같은 말이다) 양방향 관계에서 @OneToMany는  주인이 될 수 없다. 관계형 데이터베이스 특성상 일대다, 다대일 관계는 항상 '다'쪽에 외래 키가 있다. 따라서 연관관계의 주인은 항상 @ManyToOne이다. 

 

그렇다고 일대다 양방향 매핑이 완전히 불가능하지는 않다. 일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방행 매핑을 읽기 전용으로 추가하면 된다.

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    
    private String username;
    
    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;
    

    ...
 
}

@Entity
public class Team {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    
    @OneToMany
    @JoinColumn(name = "TEAM_ID") //MEMBER테이블의 TEAM_ID(FK)
    private List<Member> members = new ArrayList<Member>();
    
    private String name;
    
    ...
    
}

둘 다 같은 키를 관리하므로 문제가 될 수 있지만 Member의 JoinColumn속성을 보면 읽기만 가능하게 했다. 이 방법은 다대일 양방향처럼 보이게하지만 일대다 단방향 매핑이 가지는 단점을 그대로 가진다. 웬만하면 다대일 양방향 매핑을 사용하자.

 


[ 참고 자료 ]

 

 

https://jgrammer.tistory.com/entry/JPA-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-1-%EB%8B%A4%EB%8C%80%EC%9D%BC-%EC%9D%BC%EB%8C%80%EB%8B%A4-1

 

[JPA] 다양한 연관관계 매핑 (1) 다대일, 일대다

엔티티의 연관관계를 매핑할 때는 3가지를 고려해야한다. 다중성 단방향, 양방향 연관관계의 주인 먼저 두 엔티티가 일대일 관계일지 일대다 관계인지 다중성을 고려한다. 다음으로, 두 엔티티

jgrammer.tistory.com

 

https://jeong-pro.tistory.com/231

 

JPA 연관 관계 한방에 정리 (단방향/양방향, 연관 관계의 주인, 일대일, 다대일, 일대다, 다대다)

JPA에서 가장 중요한 것 JPA에서 가장 중요한 것을 뽑자면, "객체와 관계형 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는 것"이라고 생각합니다. 🏅 왜냐하면 JPA의 목적인 "객체 지향 프

jeong-pro.tistory.com

 

'Coding > Spring' 카테고리의 다른 글

[27] Spring AOP  (0) 2022.12.14
[26] OAuth / 소셜 로그인  (0) 2022.12.14
[24] ERD(Entity Relationship Diagram)  (0) 2022.12.13
[23] Spring Security  (0) 2022.12.13
[22] 항해99 주특기 숙련주차 시험 Spring  (0) 2022.12.08

프로젝트를 구현하기 전 미리 설계해야 할 부분이 두 가지 있다면, 

1. ERD 설계

2. API 설계 

일 것이다. 지난 번에 Restful한 API 에 대한 글을 정리했으므로 오늘은 ERD를 정리해 보려 한다.

RESTful API 설계 가이드 (참고 자료)

 


1. ERD

① ERD (Entity Relationship Diagram)

  • 개체-관계 모델. 테이블간의 관계를 설명해주는 다이어그램이다.
  • 프로젝트에서 사용되는 DB의 구조를 한눈에 파악할 수 있다. 즉, API를 효율적으로 뽑아내기 위한 모델 구조도라고 생각하면 된다.
  • DB를 개발하기 전에 보다 많은 아이디어를 도출하고, 데이터베이스 설계의 이해를 높이기 위해 데이터 모델링을 실시한다.
  • 쿼리문을 작성할 때 테이블들이 구조화된 다이어그램을 보면서 도움을 받을 수 있다.
  • 데이터의 다양한 특징을 확인할 수 있어 요구사항을 그에 맞게 개발할 수 있다.

 

ERD의 Notation

 

 

  • 기본 요소는 Entity, Attribute, Relationship 
  • 확장하여 Weak Entity, Multivalued Attribute, Weak Relationship 이 있다.

     

Entity

  • Entity는 관리하고자 하는 정보의 실체이며, 사람, 객체 혹은 개념이라고 이해하면 된다.
  • 데이터베이스를 설계할때, 쉽게는 테이블이 Entity로 정의될 수 있다.
  • 모든 Entity는 하나 이상의 식별자 (UID)를 지녀야 하며, UID가 없다면 Entity라고 할 수 없다.
  • 존재하는 다른 Entity에 의존적인 Entity를 Weak Entity라고 한다.

 

 

Attribute

  • Attribute는 Entity를 구성하고 있는 구성 요소이다.
  • 데이터 타입을 반드시 같이 명시해줘야 한다.

  • Key Attribute : 다른 객체들과 중복되지 않는 고유한 값을 가진 Attribute로, 객체를 식별하는 데 사용된다.
  • Composite Attribute : 독립적인 Attribute들이 모여서 생성된 Attribute를 의미한다.
  • Multi-Valued Attribute : 하나의 Attribute가 여러개의 값을 가지는 Attribute를 의미한다.
  • Derived Attribute : 이는 다른 Attribute가 갖고 있는 값으로부터 유도된 속성을 의미한다.

 

Relationship

  • Entity간의 관계(상호작용)를 의미한다.
  • 두 Entity간에 선을 긋고, 관계 명칭을 기록하게 된다.
  • 선택 사항을 표시한다.
    • 점선은 선택적인 사항을 의미한다. 예를 들어, 사원과 부서 Entity가 있을때 부서 입장에서는 사원을 배치 받을수도, 받지 않을 수도 있다.
    • 실선은 필수적인 사항을 의미한다. 사원 입장에서는 부서가 필수적으로 배정받아야 한다.
  • 관계 형태를 표시한다.
    • 삼지창 모양은 하나 이상을 의미한다.
    • 단선은 하나를 의미한다. 부서는 여러명의 사원을 가질 수 있으나, 사원은 하나의 부서에만 배치된다.

 

Cadinality and Ordinality

  • Entity들 간의 관계에 대한 추가 정보
  • One to many, many to many 관계를 나타낼 수 있음

여러 기호들로 관계를 표현할 수 있으나, 기호들만 숙지하여도 충분히 표현이 가능하다.

 

 

 

2. ERD 설계 사이트

https://www.erdcloud.com/

 

ERDCloud

Draw ERD with your team members. All states are shared in real time. And it's FREE. Database modeling tool.

www.erdcloud.com

 

위의 링크에서 구현할 코드의 ERD를 만들 수 있다.

아래 다이아그램은 이번 주특기 심화주차 레벨2 ERD를 설계한 모델인데, 확실히 ERD를 통해 직관적으로 테이블의 연관관계를 파악할 수 있다.

 

 

 

 

3. IntelliJ 에서 작성한 ERD 확인 하는법

 

 

  • 위와 같이 Show Entity Relationship Diagram 을 클릭하면 아래와 같이 작성한 코드의 테이블 관계를 확인 할 수 있다.

 

 

4. [DATABASE] 식별과 비식별 관계

  • 기본키(PK) :  테이블의 하나의 행의 여러 정보들 중 이를 식별해 낼 수 있는 정보
  • 외래키(FK) : 테이블간의 관계(참조하는 테이블과 참조되는 테이블 간의 관계)를 나타내는 정보
  • 외래키를 사용하여 참조하고 참조되는 두 테이블간의 관계에 따라 식별관계와 비식별관계로 나눌 수 있다.

 

식별관계 : 식별관계는 실선으로 나타내 준다.

  • 상품과 주문의 다대다 관계의 두 테이블이 있다. 상품 테이블에서는 상품번호가 기본키이고 주문테이블은 주문번호가 기본키이다.
  • 상품과 주문테이블 사이에 주문_상품 테이블을 만들어 일대다 관계로 연결하면 아래와 같다.
  • 상품테이블과 주문테이블의 기본키인 상품번호와 주문번호가 주문상품 테이블의 외래키가 되었다.
  • 그리고 이 두 외래키는 주문상품테이블의 정보를 식별할 수 있는 기본키(2개이상의 컬럼도 기본키로 구성될 수 있다.)의 역할도 하게된다. 이러한 관계를 식별관계라고한다.

 

식별관계에 대해 정리를 해보자면

  • 부모테이블(상품, 주문테이블) 기본키(PK)가 자식 테이블(주문_상품)의 외래키이자 기본키로 사용되는 관계이다.
  • 자식 테이블의 행(정보)를 추가할 때 부모테이블의 참조 행(상품번호 또는 주문번호)이 없다면 자식테이블의 행을 추가 할 수 없다.
    : 주문_상품테이블은 상품번호와 주문번호 중 하나라도 없다면 기본키를 만들 수 없게 되고(두개의 외래키가 합쳐 기본키가 되므로) 기본키가 없어 정보를 식별할 수 없으므로 데이터를 넣을 수 없다.
    : 예를 들면 게시판의 작성글과 댓글의 관계를 식별관계라고 할 수 있다.(작성글이 없다면 댓글도 없다)

 

비식별관계 : 비식별관계는 점선으로 표시한다.

 

  • 부모 테이블을 참조한 테이블에서 참조된 외래키가 기본키가 아닌 일반속성(컬럼)으로 참조되었을 때를 말한다.
  • 위의 그림의 주문_상품테이블에 정보를 식별할 수 있는 기본키를 추가하면 다음과 같다.
  • 주문상품번호라는 기본키를 추가하였다. 주문상품번호로 주문_상품테이블의 정보들을 식별할 수 있게 되고 외래키(상품번호와 주문번호)는 테이블의 일반속성이 되었다.

 

 

비식별관계에 대해 정리하면

  • 부모 테이블(상품, 주문테이블) 기본키가 자식 테이블(주문_상품테이블)의 일반컬럼이나 외래키(Foreign Key) 컬럼에 저장되는 관계이다.
  • 자식 테이블의 행(정보)를 추가할 때 부모테이블의 참조 행(상품번호 또는 주문번호)이 없어도 자식테이블의 행을 추가 할 수가 있다.
    : 예를 들면 회사의 부서와 사원의 관계를 비식별관계라고 할 수 있다. (사원이 부서가 배정되지 않을 수도 있으므로)

여기서 하나 참고할 부분에 대해 말하자면 위의 그림에서 비식별관계는 주문상품번호라는 기본키를 임의로 추가하여 만들었다. 이렇게 추가한 키를 인조키라고 하는데 기본키를 인조키로 설정하는 것이 권장된다.
이유는 식별관계를 나타내는 그림에서 보면 상품번호와 주문번호 두개의 키가 주문상품테이블의 기본키로 되어있다. 기본키는 최대한 변하지 않는 값이어야하는데 어떤이유에서 상품번호 또는 주문번호가 변경이 된다던지 사용을 할 수 없게 된다면 데이터 구조를 다시 만들어야하는 경우가 발생하기 때문이다.

 

[참고 자료]

'Coding > Spring' 카테고리의 다른 글

[26] OAuth / 소셜 로그인  (0) 2022.12.14
[25] JPA 다양한 연관관계 매핑  (0) 2022.12.13
[23] Spring Security  (0) 2022.12.13
[22] 항해99 주특기 숙련주차 시험 Spring  (0) 2022.12.08
[21] ORM, JPA, Spring Data JPA  (0) 2022.12.08

Spring Security

① Spring Security 란?

'Spring Security' 프레임워크는 스프링 서버에 필요한 인증 및 인가를 위해 많은 기능을 제공해 줌으로써 개발의 수고를 덜어 준다. 마치 '스프링' 프레임워크가 웹 서버 구현에 편의를 제공해 주는 것과 같다.

더보기

Spring Boot automatically:

  • Enables Spring Security’s default configuration, which creates a servlet Filter as a bean named springSecurityFilterChain. This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the login form, and so on) within your application.
  • Creates a UserDetailsService bean with a username of user and a randomly generated password that is logged to the console.
  • Registers the Filter with a bean named springSecurityFilterChain with the Servlet container for every request.

 

② 스프링 시큐리티 적용하는 방법

  • build.gradle에 스프링 시큐리티 프레임워크 추가
// 스프링 시큐리티
implementation 'org.springframework.boot:spring-boot-starter-security'
  • WebSecurityConfig (springboot 2.7이상) 파일로 스프링 시큐리티 활성화 하기
package com.sparta.springsecurity.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf().disable();
        
        http.authorizeRequests().anyRequest().authenticated();

        // 로그인 사용
        http.formLogin();
        
        return http.build();
    }

}

 

③ CSRF(사이트 간 요청 위조, Cross-site request forgery)

  • 공격자가 인증된 브라우저에 저장된 쿠키의 세션 정보를 활용하여 웹 서버에 사용자가 의도하지 않은 요청을 전달하는 것
  • CSRF 설정이 되어있는 경우 html 에서 CSRF 토큰 값을 넘겨주어야 요청을 수신 가능
  • 쿠키 기반의 취약점을 이용한 공격 이기 때문에 REST 방식의 API에서는 disable 가능
  • POST 요청마다 처리해 주는 대신 CSRF protection 을 disable 

 

Spring Security 주요 컴포넌트

① Spring Security 와 Filter

  •  Spring Security는 요청이 들어오면 Servlet FilterChain을 자동으로 구성한 후 거치게 한다.
  • FilterChain은 여러 Filter를 chain형태로 묶어놓은 것을 의미
  • 여기서 Filter 란, 톰캣과 같은 웹 컨테이너에서 관리되는 서블릿의 기술이다.
  • Filter는 Client 요청이 전달되기 전후의 URL 패턴에 맞는 모든 요청에 필터링을 해준다. CSRF, XSS 등의 보안 검사를 통해 올바른 요청이 아닐 경우 이를 차단해 준다. 따라서 Spring Security는 이런한 기능을 활용하기위해 Filter를 사용하여 인증/인가를 구현하고 있다.

② SecurityFilterChain

  • session, jwt 등의 인증방식들을 사용하는데에 필요한 설정을 완전히 분리할 수 있는 환경을 제공한다.

 

③ AbstractAuthenticationProcessingFilter : 사용자의 credential을 인증하기 위한 베이스 Filter

 

 

④ UsernamePasswordAuthenticationFilter

  • UsernamePasswordAuthenticationFilter 는 AbstractAuthenticationProcessingFilter를 상속한 Filter다.
  • 기본적으로 아래와 같은 Form Login 기반을 사용할 때 username 과 password 확인하여 인증한다.
  • Form Login 기반은 인증이 필요한 URL 요청이 들어왔을 때 인증이 되지 않았다면 로그인페이지를 반환하는 형태이다.

 

⑤ SecurityContextHolder

 

  • SecurityContextHolder 에는 스프링 시큐리티로 인증을 한 사용자의 상세 정보를 저장한다.
  • SecurityContext 란? SecurityContextHolder 로 접근할 수 있으며 Authentication 객체를 가지고 있다.

Authentication

  • 현재 인증된 사용자를 나타내며 SecurityContext 에서 가져올 수 있다.
  • principal : 사용자를 식별한다. Username/Password 방식으로 인증할 때 보통 UserDetails 인스턴스다.
  • credentials : 주로 비밀번호, 대부분 사용자 인증에 사용하고 다음 비운다.
  • authorities : 사용자에게 부여한 권한을 GrantedAuthority 로 추상화하여 사용한다.
  • UsernamePasswordAuthenticationToken는 Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, 인증객체를 만드는데 사용된다.

UserDetailsService : username/password 인증방식을 사용할 때 사용자를 조회하고 검증한 후 UserDetails를 반환한다. Custom하여 Bean으로 등록 후 사용 가능하다.

 

검증된 UserDetails : UsernamePasswordAuthenticationToken 타입의 Authentication를 만들 때 사용되며 해당 인증객체는 SecurityContextHolder에 세팅된다. Custom하여 사용가능하다.

+ Recent posts