[서버개발캠프] Spring boot + Spring security + Refresh JWT + Redis + JPA 1편

Sieun Sim·2020년 1월 17일
15

서버개발캠프

목록 보기
2/21

ORM과 JPA란?

  • ORM: Object-relational mapping (객체 관계 매핑)
    객체는 객체대로 설계하고, 관계형 데이터베이스는 관계형 데이터베이스대로 설계한다.
    ORM 프레임워크가 중간에서 매핑해준다.

  • JPA: Java Persistence API

    ORM을 사용해 오브젝트와 RDB 사이에 존재하는 개념과 접근을 객체지향적으로 다루기 위한 기술
    관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스의 모음. 특정 기능을 하는 라이브러리가 아니고 실제로 동작하는 것도 아니다.

    일반적인 백엔드 API가 클라이언트가 어떻게 서버를 사용해야 하는지를 정의한 것처럼, JPA 역시 자바 어플리케이션에서 관계형 데이터베이스를 어떻게 사용해야 하는지를 정의하는 한 방법

JPA의 동작 과정

image.png

JPA는 애플리케이션과 JDBC 사이에서 동작한다.
개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다.
즉, 개발자가 직접 JDBC API를 쓰는 것이 아니다.

  • 저장 과정
    image.png

Ex) MemberDAO에서 객체를 저장하고 싶을 때
개발자는 JPA에 Member 객체를 넘긴다.
JPA는

  1. Member 엔티티를 분석한다.
  2. INSERT SQL을 생성한다.
  3. JDBC API를 사용하여 SQL을 DB에 날린다.
  • 조회 과정
    image.png

Ex) Member 객체를 조회하고 싶을 때
개발자는 member의 pk 값을 JPA에 넘긴다.
JPA는

  1. 엔티티의 매핑 정보를 바탕으로 적절한 SELECT SQL을 생성한다.
  2. JDBC API를 사용하여 SQL을 DB에 날린다.
  3. DB로부터 결과를 받아온다.
  4. 결과(ResultSet)를 객체에 모두 매핑한다.
    쿼리를 JPA가 만들어 주기 때문에 Object와 RDB 간의 패러다임 불일치를 해결할 수 있다.

참고:

[JPA] JPA란 - Heee's Development Blog

Hibernate란?

Hibernate는 JPA라는 명세의 구현체이다. 즉, 위에서 언급한 javax.persistence.EntityManager와 같은 인터페이스를 직접 구현한 라이브러리이다. JPA와 Hibernate는 마치 자바의 interface와 해당 interface를 구현한 class와 같은 관계이다.

Spring Data JPA는?

Spring Data JPA는 Spring에서 제공하는 모듈 중 하나로, 개발자가 JPA를 더 쉽고 편하게 사용할 수 있도록 도와준다. 이는 JPA를 한 단계 추상화시킨 Repository라는 인터페이스를 제공함으로써 이루어진다. 사용자가 Repository 인터페이스에 정해진 규칙대로 메소드를 입력하면, Spring이 알아서 해당 메소드 이름에 적합한 쿼리를 날리는 구현체를 만들어서 Bean으로 등록해준다.

!!!소중한 그림!!!

image.png

출처:

JPA, Hibernate, 그리고 Spring Data JPA의 차이점


@RequestBody와 @RequestParam의 차이

전자는 Json 객체로, 후자는 지정한 자료형으로. React axios를 사용했을 때 자동으로 json으로 데이터를 전달하므로 @RequestParam으로 받지 않도록 주의하기 (오늘의 삽질)

Java의 Iterable

iterable은 순회할 수 있는 컬렉션을 나타낸다. Iterable 인터페이스를 implement하면 객체는 for-each loop를 사용할 수 있게 해준다. (내부적으로 iterator() 메소드를 객체에 호출해서 가능)

List같은 컬렉션의 상위 개념인듯


Mysql on Ubuntu

$ service mysqld status // 상태확인
$ service mysqld stop // 서비스 종료
$ service mysqld start //서비스 시작

$ mysql -u <Username> -p<Password>

application.properties 설정하기

## MySQLspring.datasource.url=jdbc:mysql://localhost:3306/pj2?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=gkgk1212

#`hibernate_sequence' doesn't exist
spring.jpa.hibernate.use-new-id-generator-mappings=false

# drop n create table, good for testing, comment this in production
spring.jpa.hibernate.ddl-auto=update

serverTimezone 설정 잊지말기.

인증 방식 선택.

근래 모바일 트렌드 중 하나는 로그아웃을 하지 않는 이상 로그인을 유지하는 것입니다. 일반적으로는 손쉽게 Session을 이용해서 클라이언트와 서버 통신 중 Stateless의 단점을 보완할 수 있었지만, 모바일의 특성상 자주 끊길 소지가 있습니다. 세션과 비슷한 역할을 하되, 계속해서 유지될 수 있는 기술을 찾다 보니 Token을 이용한 방식이 있었고, 그중 JWT를 사용하게 되었습니다.

Ubuntu에서 Yarn start Error

이유는 모르겠는데 sudo권한으로 실행해야 에러안남...

Salt의 목적

비밀번호가 해킹할 해쉬와 동일한 방법으로 해싱되어 있으면 룩업 테이블, 레인보우 테이블로 무작위로 막 넣어서 찾는 해킹이 가능하다. 만약 두 사용자가 동일한 비밀번호를 사용한다면 이들은 동일한 해싱 비밀번호를 가지게 된다. 

Salt를 모르므로 미리 db를 생성해두는 것을 방지하는 것임

Salt는 DB가 털렸을 때를 방지한다기보다 규칙찾기 방지 같은 느낌.

The goal of the salt is only to prevent pre-generated databases from being created

Sping Security의 원리를 잘 정리해둔 링크

https://coding-start.tistory.com/153

Spring Security를 적용하면 벌어지는일

알아서 login 페이지를 만들어서, 설정을 해제해주지 않으면 자동으로 거기로 감.

Crossorigin을 controller에 설정한 것 만으로는 적용이 안됨. servlet으로 가기전에 처리하는거라서...

모든 유저에게 permit all 하고 모든 origin에 대해 허용하도록 설정해주자

출처: https://oddpoet.net/blog/2017/04/27/cors-with-spring-security/

@Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/**").permitAll();

        http
                /*... 중략 ...*/
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() // - (1)
                /* 중략 */
                .anyRequest().authenticated().and()
                .cors().and(); // - (2)
    }


@Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        // - (3)
        configuration.addAllowedOrigin("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

Role 설정의 중요성

The configuration will require that any URL that is requested will require a User with the role "ROLE_USER"

Httpsecurity 공식 문서:

HttpSecurity (Spring Security 4.2.13.RELEASE API)

User는 Spring security 내부에서 사용하는거. Role까지 정해져 있어야만 request가 정상적으로 수행되는 듯하다. Role을 설정하지 않고 요청하면 403 forbidden을 반환하더라

http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/**").permitAll();dmin/**").hasRole("ADMIN")        .antMatchers("/**").permitAll();

@Joincolumn name이 오류 내는 이유

실제 db가 연동되어 있지 않아서. 그냥 warning으로 이해하고 무시해도 될 듯!

해결하는방법은 https://stackoverflow.com/questions/29155350/jpa-cannot-resolve-column-intellij

Arrays.asList()

Arrays.asList()는 Arrays의 private 정적 클래스인 ArrayList를 리턴한다.

java.util.ArrayList 클래스와는 다른 클래스이다. java.util.Arrays.ArrayList 클래스는 set(), get(), contains() 메서드를 가지고 있지만 원소를 추가하는 메서드는 가지고 있지 않기 때문에 사이즈를 바꿀 수 없다.

자바 직렬화란?

  • 자바 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기합니다.
  • 시스템적으로 이야기하자면 JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 이야기합니다.
  • 즉 jwt 이런데에 정보 담기 위해 객체 자체를 바이트화 시키려고 사용

@Component와 @Bean의 차이

@Component는 개발자가 직접 작성한 Class를 Bean으로 만드는 것이고, @Bean은 개발자가 작성한 Method를 통해 반환되는 객체를 Bean으로 만드는 것이다.
출처: https://galid1.tistory.com/494

3개의 댓글

comment-user-thumbnail
2020년 8월 11일

안녕하세요. 개인적으로 Oauth 공부를 하고 있는 사람입니다. git에 올린 소스는 없으신가요?ㅠ

1개의 답글
comment-user-thumbnail
2021년 3월 2일

감사합니다ㅠㅠ

답글 달기