Spring/SpringSecurity

Spring Boot JWT Tutorial (1)설정, DB

finepiz 2022. 4. 12. 12:06

===

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-jwt/dashboard

 

[무료] Spring Boot JWT Tutorial - 인프런 | 강의

Spring Boot, Spring Security, JWT를 이용한 튜토리얼을 통해 인증과 인가에 대한 기초 지식을 쉽고 빠르게 학습할 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

Q.

52초쯤 JWT를 적용함에 있어서 몇가지 고려해야할

사항들을 잘 대응하면 대규모 프로젝트에서도 적용할 수 있다고 하셨는데요!

고려해야될 사항을 좀 더 추가로 설명을 해주시면

감사하겠습니다!

A.

고려해야될 사항이라는 것은 해당 시스템의 요구사항에 따라 수많은 사항들이 생길 것 같다고 생각합니다.

가장 간단한 예를 든다면 

가령 "시스템은 사용자에게 발급된 토큰 중 특정 토큰을 지정하여 사용을 중지시킬 수 있다" 라는 요구사항이 있다고 한다면 

토큰의 만료시간만 가지고 해당 요구사항을 충족시킬 수는 없겠죠. 그때는 서버사이드에서 해당 요구사항을 충족하기 위한 추가 개발들을 해야할 것 이라고 생각이 듭니다.

이 요구사항을 충족하기 위해 몇가지 생각해보면 아래와 같은 방법들이 있을 것 같습니다.

 - 권한 DB의 Version 정보를 관리해서 권한이 수정되면 Version을 변경하고 JWT 내의 Version 정보와 비교해서 틀리면 Update 
 - JWT 만료 날짜를 짧게 유지한다.

 - 토큰을 Redis 혹은 DB 같은곳에 저장해놓고 권한이 변경되면 해당 토큰을 업데이트 대상 토큰으로 저장하여 놓고 권한이 필요한 API를 요청할 시 업데이트 대상 토큰을 검증하는 필터를 구현하여 업데이트
 - JWT 페이로드에 발급 시간을 저장해 놓고 권한이 변경된 시간과 비교 업데이트 

 

일단은 JWT의 기초 지식에 대해 먼저 습득하신 후에 실제 본인만의 서비스를 만들어서 적용해보시길 추천드립니다. :)

 

===

JWT : 

RFC 7519 웹표준 JSON

객체를 사용해서 토큰 자체에 정보들을 저장하고 있는 Web Token

간편하고 쉽게 적용 가능

 

===

Header : Signature를 해싱하기 위한 알고리즘 정보를 담는다

Payload : 서버와 클라이언트가 주고받는, 시스템에서 실제로 사용될 정보에 대한 내용들을 담는다

Signature : 토큰의 유효성 검증을 위한 문자열, 서버가 체크함

 

===

 

===

[실습]

Spring Web, Spring Security, Spring Data JPA, H2, Lombok, Validation

IntelliJ를 쓰면 Lombok을 쓸 때 저걸 체크해야

 

===

이 상태인데 

 

▽실행을 하려니까

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
//implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
//testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

얘네를 추가하고 h2안쓸것같지?하면서 주석처리 하고

실행했더니

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

 

아하?주석뺐더니

Unauthorized가 뜬다.

(▽원래는 그냥 떠야하잖아. security다시 빼면 나온다. 요즘은 패치돼서 Body에 아무것도 안나오는듯 똑같이 프로젝트 따라해봤는데 안나옴)

 

이를 해결하기 위한 Security설정과 기본적인 Data 설정들을 진행해야한다

 

====================================

====================================

이제부터 할 것

기본적인 Security 설정을 위해 SecurityConfig 클래스를 만든다.

기본적인 Web 보안을 활성화 하겠다는 애너테이션

 

추가적인 설정을 위해 WebSecurityConfigurer를 implements하거나

WebSecurityConfigurerAdapter를 extends하는 방법이 있다

 

여기선 후자택

 

===

WebSecurityConfigurerAdapter의 configure메소드를 오버라이드

authorizeRequests : HttpServletRequest를 사용하는 요청들에 대한 접근제한을 설정하겠다

anyMatchers("/api/hello").permitAll() : /api/hello에 대한 요청은 인증없이 접근을 허용하겠다는 의미

anyRequest().authenticated() : 나머지 요청들은 모두 인증돼야 한다는 의미

 

그럼이제

잘됨

 

===

DataStore에 대한 설정

application.properties파일을 Refactor를 이용해서 application.yml로 파일명을 변경하겠습니다

(그냥 더 보기 편해서 변경한 것)

h2 DB사용, 메모리에 데이터 저장 할것

h2 console을 enable했고

Datasource 설정 추가

JPA설정 추가, create-drop은 SessionFactory가 시작될 때 Drop, Create, Alter 를 하고 / 종료될 때 Drop 진행

콘솔창에서 실행되는 sql들을 보기좋게 보여주는 설정추가

로깅레벨 디버그

 

===

create-drop은 SpringBoot 서버가 시작될 때마다 테이블들을 새로 만든다 -> 편의를 위해 초기 Data를 자동으로 DB에 넣어주는 기능을 활용하겠다

 

resource > data.sql

에다 넣으면 이 쿼리들이 실행이 된대 왜??

 

===

entity 패키지 생성, User, Authority 클래스 생성

@Entity
@Table(name = "user")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {

   @Id
   @Column(name = "user_id")
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long userId;

   @Column(name = "username", length = 50, unique = true)
   private String username;

   @Column(name = "password", length = 100)
   private String password;

   @Column(name = "nickname", length = 50)
   private String nickname;

   @Column(name = "activated")
   private boolean activated;

   @ManyToMany
   @JoinTable(
      name = "user_authority",
      joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")},
      inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")})
   private Set<Authority> authorities;
}

 

User의 애너테이션 설명 : 

@Entity : 데이터베이스의 테이블과 1:1 매핑되는 객체를 뜻함

@Table : name으로 테이블 명 이름 지정 위해 씀

 

User의 필드 설명 :

@ManyToMany, JoinTable은 User객체와 권한객체의 다대다 관계를 일대다, 다대일 관계의 조인 테이블로 정의했다는 뜻

@Entity
@Table(name = "authority")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Authority {

   @Id
   @Column(name = "authority_name", length = 50)
   private String authorityName;
}

 

===

만들었던 엔티티들이 DB에 생성이 되는지 확인하기 위해 h2-console을 이용하려고 하는데

그 전에 Security 설정을 추가해줘야 h2-console접근을 원활하게 할 수 있다.

 

SecurityConfig로 가서 configure(WebSecurity web) 메소드 오버라이드

h2-console 하위 모든 요청들과 파비콘 관련 요청은 Spring Security 로직을 수행하지 않도록

 

서버를 실행하면

실제 DB확인하기, 브라우저 열고 localhost:8080/h2-console

잘 나옴