본문 바로가기

Spring

(12)
스프링초짜의 도메인 이벤트 찍먹 도전기 (1) 사이드 프로젝트로 멘토링을 구하는 서비스를 만들고 있다. 모바일과 연동이 필요한 기능이 있었는데, 멘토링을 제안하거나 수락, 거절하게 되면 보낸 사람에게 푸시 메시지를 보내는 구조였다. 푸시 메시지는 firebase에서 제공하는 클라우드 메시징 기능을 사용하여 보내기로 했다. 메시지를 보내기 위해선 상대방의 디바이스 토큰이 필요했기 때문에 조회 로직이 반드시 들어가야 했다. (fcm: Firebase Cloude Messaging) 그런데 코드를 작성하면서 이상한 점이 들었다. 문제인식 @Transactional public void requestTutoring(RequestTutoringDto dto, TokenAccountInfo token) { Tutoring tutoring = Tutoring.b..
ArgumentResolver로 토큰에서 값 추출하기 사이드 프로젝트 중에 jwt 토큰에서 ID와 authority를 꺼내어 사용하는 일이 생겼는데, token을 발급해주는 클래스에서 처리했었다. 그런데, 최근 오브젝트라는 책을 보고 객체가 가져야 할 책임에 대해 고민하게 되었고 프로젝트에 적용해보려 한다. 코드를 잘 작성한 줄 알았는데, 역시나.. 문제가 있었다. 문제 인식 기존 코드에서는 Authorization 헤더의 값을 컨트롤러에서 받아 서비스로 전달했다. @DeleteMapping(value = "/tutorings/{tutoringId}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity cancelTutoring( @RequestHeader(name = "Authoriza..
[Spring Boot + Security] @PreAuthorize로 토큰 확인하기 웹 애플리케이션을 개발하다 보면 로그인한 계정의 정보를 보여주는 마이페이지 등을 구현해야 할 때가 생긴다. 그런데 다른 계정의 토큰을 가진 사람이 여기에 접근하면 보안상 문제가 있기 때문에 컨트롤러 혹은 서비스에서 토큰 내부의 ID 값과 요청하는 ID 값을 확인하는 로직을 넣어주어야 한다. 문제 인식: 위처럼 요청하는 ID가 발급된 토큰 내부의 ID값과 일치하는지 확인하는 코드를 비즈니스 로직에 추가해주어야 한다. 그런데 비즈니스와는 상관없는 관심사 코드가 매번 들어가야 하므로 응집도가 떨어지는 단점이 있었다. 그래서 몇 가지 방법을 생각해봤다. 방법 1: token을 발급해주는 tokenProvider Bean 내부에서 검증해주는 로직을 작성하여 컨트롤러 or 서비스 내부에 넣는다. -> 처음에 이 방..
SpringBoot 중요한 설정 숨기기 스프링부트를 사용하여 개발하다 보면 여러 property들을 관리할 일이 생긴다. github와 같은 오픈된 저장소를 사용할 때 중요한 시크릿 키들을 같이 올리면 탈취당할 우려가 있다. 따라서 이러한 설정들을 숨기기 위해 내가 사용한 방법을 정리하고자 한다. 프로퍼티 우선 순위 1. 유저 홈 디렉토리에 있는 spring-boot-dev-tools.properties 2. 테스트에 있는 @TestPropertySource 3. @SpringBootTest 애노테이션의 properties 애트리뷰트 4. 커맨드 라인 아규먼트 5. SPRING_APPLICATION_JSON (환경 변수 또는 시스템 프로티) 에 들어있는 프로퍼티 6. ServletConfig 파라미터 7. ServletContext 파라미터 ..
SpringSecurity + CustomAuthenticationProvider 만들기 Rest API로 만든 메서드에 로그인 시도를 하면 아이디와 비밀번호가 틀렸을 때 어느 부분이 틀렸는지를 알려주려 하는데, 스프링 시큐리티에서는 AuthenticationProvider 디폴트 구현체가 내부적으로 인증을 수행하여 반환한다. 따라서 아이디와 비번이 틀린 경우에 따라 오류 메시지를 다르게 하기 위해서는 AuthenticationProvider를 커스텀하여 인증을 직접 수행해야 한다. 다행히도 스프링 시큐리티에선 이러한 부분들을 구조화 해놓았기 때문에, 인터페이스만 맞추어 구현하기만 하면 된다. 내가 수행하는 부분은 4이다. AuthenticationManager가 AuthenticationProvider에게 인증 책임을 넘기게 되는데, CustomAuthenticationProvider 구현..
Filter, Interceptor, AOP 차이에 대한 정리 공통 프로세스에 대한 고민 자바 웹 개발을 하다보면, 공통적으로 처리해야 할 업무들이 많다. 예를들어 로그인 관련(세션체크)처리, 권한체크, XSS(Cross site script)방어, pc와 모바일웹의 분기처리, 로그, 페이지 인코딩 변환 등이 있다. api마다 공통 로직을 작성하게 되면 코드 중복으로 인해 관리하기 까다로워지고, 다른 도메인 로직에 섞여들기 때문에 가독성을 해친다. 따라서 공통 로직을 한 곳에 모으고, 선택적으로 적용하는 것이 필요하다. Spring에서 위와 같은 상황에 적용하기 위한 3가지 방법이 있다. Filter, Interceptor, AOP의 흐름 - Interceptor와 Filter는 Servlet 단위에서 실행된다. 반면 AOP는 Proxy 패턴으로 실행된다. - 요청..
오늘의 질문: jpql 프로젝션 대상이 둘 이상이면 반환 값을 어떻게 받나? 간단한거지만 개념이 헷갈려서 기록해두려 한다. SQL에서는 select 절에 여러 값을 반환받을 수 있다. 그렇다면 jpql에서는 어떻게 반환받아야 하나? 반환 값이 하나라면 select [변수명] from 객체 선언... 으로 간단하게 가져올 수 있는데 여러 개는 처음이라 헷갈렸다. 생각했던 방법은 크게 두가진데 첫 째 Query Projection용 DTO 클래스를 사용한다. jpa 강의에서 배운 방법이지만, Infra 영역이 DTO에 의존하게 되어 꺼려졌다. 뿐만 아니라 DTO 특성상 다른 레이어에 의존 관계가 생겨서 별로 좋지 못한 방법같았다. 둘 째 자바의 Object[] 타입으로 받는다. 참고: https://stackoverflow.com/questions/6877857/jpa-query-t..
오늘의 질문 : JPA 엔티티 수정 방식 Q. jpa에서 조회한 엔티티를 업데이트할 때 실무에선 어떤 방식으로 업데이트하시는지 궁금합니다. 1. 엔티티 내부에 id를 제외한 모든 파라미터를 받는 수정자 메서드를 생성 2. builder로 객체를 clone하고, 빌더를 이용한 수정자 메서드 생성 3. 업데이트할 필드의 내용으로 새 엔티티를 생성하고, id를 복사 불변, 신뢰성때문에 되도록이면 수정자 메서드를 넣지 않고, 식별자를 copy하여 객체를 새로 만드는 방식을 생각했었는데, 답변을 보니 생각이 달라졌다. 고찰 : 1. 도메인 로직에 수정 메서드를 넣고, 수정하는 책임을 지게 하는게 깔끔하다. 2. 불변이 꼭 만능은 아니며, jpa의 엔티티 논리적 동치관계는 ID로 하기 때문에, 굳이 새로만들어서 불변성 보장을 시도하지 않아도 된다. 3. ..
DDD를 위한 일대다 연결관계 매핑 요구사항 정의 시험은 N개의 문제를 가진다. 문제 등록은 시험이 있어야 가능하다. 문제의 생성, 수정, 삭제, 조회는 시험을 통해서만 가능하다. 시험이 삭제되면, 문제들도 삭제된다. 시험과 문제는 각각 유니크한 식별자를 가진다. 하위 엔티티들을 관리하기 위한 전략 시험에 있어서 문제는 관리해야 할 하위 엔티티이다. 시험을 통해서만 문제가 등록되도록 영속성 전이 옵션 (cascade)을 사용한다. 생성, 수정, 삭제의 관점에서 보자. 생성은 상위 엔티티의 컬렉션에 하위 엔티티를 넣어 영속 상태로 만들면 JPA에서 insert 해준다. 수정은 조회 후 컬렉션의 원소를 수정하여 영속 상태로 만들면 JPA에서 update 해준다. 삭제는 조회 후 컬렉션의 원소를 삭제하여 영속 상태로 만들면 JPA에서 delet..
JPA 생성 날짜, 수정 날짜 자동으로 넣어주기 JPA에서 ORM을 이용해 데이터베이스의 컬럼과 매핑할 때 공통적으로 들어가는 기능들이 있다. 대표적으로 생성 일자나 수정 일자 등이 있는데, 비즈니스 로직상 들어가지 않는 경우도 있겠지만 대부분 공통적으로 들어간다. 그래서 미리 만들어 놓은 기능이 있다. Autiting(감시) 옵션인데, 엔티티들의 변경을 감지하여 필드를 갱신하게 된다. 이러한 변경 감지 옵션을 사용하기 위해선 스프링부트에서 활성화하려면 @EnableJpaAuditing 어노테이션을 붙여줘야 한다. @SpringBootApplication @EnableJpaAuditing public class BookshopApplication { public static void main(String[] args) { SpringApplicatio..