2021.05.12 ~ 2021.05.19
인증 : 식별 가능한 정보로 서비스에 등록된 유저의 신원을 입증하는 과정(로그인)
인가 : 인증된 사용자에 대한 자원 접근 권한 확인(관리자와 일반 유저의 차이)
인증이 인가보다 먼저 진행되어야한다.
Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 말한다.
JWT는 크게 3부분으로 나눠져있다. JWT의 각 부분은 독립적으로 만들어진다.
header.payload.signature
(https://jwt.io/)
header: 암호화 방식(alg), 토큰의 타입(type) 등이 들어가있다. base64로 인코딩한다.
payload: 서버에서 클라이언트에게 보낼 데이터가 들어가 있다. 주로 식별자를 담는다. 이때 비밀번호와 같은 중요한 정보는 담으면 안된다. 토큰 제목(sub), 토큰이 발급된 시간(iat) 등의 정보도 포함된다. 여기에 담기는 정보 하나하나를 클레임이라고 부른다. 즉, 위의 그림에는 sub, iat, name 총 3개의 클레임이 담겨있다. base64로 인코딩한다.
signature: header의 인코딩 값과, payload의 인코딩 값을 합친 후, 주어진 비밀키로 해쉬하여 생성한다. 해쉬한 값을 base64로 인코딩한다.
header와 payload는 누구나 디코딩 할 수 있기 때문에 payload에 중요한 정보를 담으면 안되는 것이다.
토큰을 사용하면, 세션과 달리 별도의 저장소 관리가 필요없다. 또 확장성도 뛰어나다. 그렇지만 accessToken이 탈취되면 문제가 생긴다. 그래서 accessToken의 만료시간은 짧게 설정하고 RefreshToken을 사용한다.
(나중에 JWT 비대칭키 알아보기)
참고
[ springboot ] JWT + 스프링부트
쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT)
[JWT] JSON Web Token 소개 및 구조
[10분 테코톡] 🎡토니의 인증과 인가
크게 토큰을 저장하는 위치는 2가지가 있다. 1) 로컬 스토리지, 2) 쿠키
로컬 스토리지: 브라우저에 데이터를 저장한다. 이 방법은 보안이 좋지 못하다. 브라우저는 자바스크립트로 제어가 가능하기 때문에, XSS 공격에 취약하다.(해커가 자바스크립트 코드를 웹 페이지에 심어 사용자의 정보를 탈취하는 공격)
쿠키: 쿠키 내부에 토큰을 저장해둔다. 쿠키 또한 자바스크립트로 조작이 가능하다. 다만 쿠키는 HttpOnly 옵션 설정에 따라 자바스크립트 조작을 막을 수 있다. 쿠키 생성시 이 옵션을 주면 자바스크립트로 접근이 불가하며 http 통신을 통해서만 쿠키가 전송된다. 따라서 XSS 공격을 방어 할 수 있다. 하지만 쿠키는 CSRF 공격에 취약하다.(사용자가 자신의 의지와 무관하게 공격자가 의도한 행위를 특정 웹 사이트에 요청하게 만드는 공격)
그래도 둘 중에 쿠키가 좀 더 보안적으로 좋다고 한다. 로컬 스토리지 보다는 방어책이 많이 알려져있기 때문이다.
참고
JWT 토큰은 어디에 저장하는게 좋을까?
[Web] HTTP Only와 Secure Cookie 이해하기
Controller의 파라미터로 미리 가공된 원하는 객체를 받기 위한 것.
[새배내] 스프링 입문 - 체스 미션을 하며 새로 배운 내용 ArgumentResolver 부분 참고
둘 다 공통되는 부분을 처리하기 위한 것이다.
Filter - Dispatcher Servlet - Interceptor - Controller
Filter가 먼저 실행되고, Interceptor가 실행된다.
Dispatcher Servlet 전 Front Controller 앞 에서 실행된다. 스프링 컨텍스트 이전에 실행되므로 스프링과 무관하다. 인코딩 변환, 보안 처리(ex. XSS 방어) 등에 사용한다.
DispatcherServlet이 Controller를 호출하기 전이나 후에 실행된다. 스프링 컨텍스트 내부에서 실행된다. 권한 확인이나 일반적인 핸들러 작업에 사용한다.
참고
[Spring] Filter, Interceptor, AOP 차이
commit 아이디는 commit의 정보를 SHA-1 해시 알고리즘을 통해 문자열로 변환한 값이다. commit의 정보가 수정되면 commit 아이디 또한 바뀐다. commit마다 고유한 값을 가지게 된다.
특정 커밋을 가져와서 현재 브랜치에 추가 할 수 있게 해주는 명령어.
이번 미션 진행중 1, 2 단계 merge 전에 다른 브랜치에서 3단계를 진행했다. 그 후 1, 2단계가 merge 되었고, 구현해놓은 커밋을 옮겨와야 했다. 이때 cherry-pick을 사용했다.
commit을 추가하기 위한 브랜치로 checkout 후, 가져오고 싶은 커밋 아이디를 cherry-pick 하면 된다.
git cherry-pick 커밋아이디
일정 범위를 모두 가져오고 싶다면
git cherry-pick 커밋아이디^..커밋아이디
참고
[Git] cherry-pick으로 원하는 commit 가져오기
[Git] cherry-pick으로 원하는 커밋 가져오기
데이터 바인딩 시 @Valid 애노테이션을 걸어주고, 데이터 필드에 @Email을 붙여주면, 해당 필드가 이메일 형식인지 검사하고, 이메일 형식이 아니라면 MethodArgumentNotValidException을 던져준다.
public class Member {
@Email
private String email;
// ...
}
pojo : 특정 기술에 종속적이지 않은 순수한 자바 객체를 뜻함.
java bean : 데이터를 표현하기 위한 java 클래스를 만들때의 규약을 지킨 객체([새배내] 스프링 입문 - 체스 미션을 하며 새로 배운 내용 - 자바 빈 부분 참고)
java bean은 pojo지만, pojo는 java bean이 아닐 수도 있다. pojo가 더 큰 개념이다.
spring bean : IoC 컨테이너에서 관리되는 객체. 컴포넌트 스캔이나, configuration을 통해 빈으로 등록된 객체
CommandLineRunner 인터페이스의 구현체를 만들고 @Component를 붙여주면 스프링 부트 구동 시점에 run(String... args)메서드를 실행한다.
ApplicationRunner 인터페이스의 구현체를 만들고 @Component를 붙여주면 스프링 부트 구동 시점에 run(ApplicationArguments args)메서드를 실행한다.
여러개의 CommandLineRunner나 ApplicationRunner 구현체를 만들 수 있고, @Order(순서) 어노테이션으로 순서를 지정해줄 수 있다.
ApplicationRunner과 CommandLineRunner 차이점은 arguments가 다르다는 것이다. 기능은 동일하다. ApplicationRunner가 더 최신에 나온 거라고 한다.
참고
스프링 부트 구동 시점에 특정 코드 실행 시키기 (CommandLineRunner & ApplicationRunner)
@Profile은 환경을 구분해주는 애노테이션이다. 개발, 테스트, 프로덕션 등 환경을 나눠줘야할때 특정 환경을 표현해준다.
@ActiveProfile은 테스트에서 사용하는 애노테이션이다. 테스트 코드에서 특정 프로파일을 지정해줘서 사용한다.
1) 서비스 계층까지 dto가 전달되어도 된다는 의견
2) 컨트롤러에서 dto를 도메인으로 바꿔 서비스로 넘겨줘야한다는 의견
정답은 없겠지만 나는 1)번 의견에 동의한다. Controller는 도메인을 직접적으로 알 필요가 없다. 오히려 내부 비즈니스 로직이 외부로 노출된다고 볼 수 있다. Controller는 최소한의 요청 / 응답에만 관심사를 두자.
엔티티는 식별자를 가지고 있다. 식별자의 의미가 두 인스턴스의 동등성을 보장해주기 때문에, 엔티티의 동등성 비교는 id값을 통해서만 해줘도 된다. 즉 equals & hashcode를 재정의 할때 id 필드만 비교해줘도 된다.
한 가지 책임을 기준으로 응집되었는지를 확인하면서 도메인을 분리한다.
어떤 도메인 내부에 private 메서드가 너무 많다면 도메인 분리를 생각해 볼 수 있다.
Raw 타입이란 제네릭 타입을 적어주지 않는 것.
List< String >의 raw 타입은 List이다.
raw 타입을 사용하면 아무 타입이나 다 허용되기 때문에 타입 안정성을 해친다. 또한 런타임에 가서야 에러를 찾을 수 있다.
따라서 raw 타입 사용을 지양해야한다.
Get 요청시 파라미터로 데이터가 넘어올 수 있다. 이 경우 @RequestParam을 사용하여 값을 얻어올 수 있다. 하지만 이런 경우 @ModelAttribute를 사용하여 객체로 받아주는 것이 더 좋다. Dto로 값을 받는다면 @Valid를 통한 validation도 해줄 수 있고, 때에 따라 바로 도메인으로 변환 등의 책임을 줄 수도 있다.
가장 단순한 DB는 하나의 서버에 하나의 DB가 연결 되어있는 구조를 가지고 있다. 그러나 사용자가 늘어날수록 하나의 DB가 모든 쿼리를 처리하기가 힘들어진다.
쿼리의 대부분은 select
이다. 리플리케이션은 DB를 하나의 Master DB, 여러개의 Slave DB로 나눠 동일한 데이터를 가지고 있게 한 후, select
요청은 Master DB의 부하를 막기 위해 Slave DB에서만 담당하게 하고, CUD요청은 Master DB에서 담당하게 한다. Master DB는 CUD를 처리한 후 Slave DB에 데이터를 동기화 시킨다.
이를 처리하기 위한 기준이 @Transactional(readOnly=true)
이다. 이 애노테이션이 붙어있다면 요청을 Slave DB로 보내는 식으로 처리한다.
참고
Database의 리플리케이션(Replication)이란?
Spring Batch ItemReader에서 Reader DB 사용하기 (feat. AWS Aurora)