Spring Security - In-Memory Authentication Warm-up

이미지
스프링 시큐리티는 모두들 러닝 커브가 높다는 것을 알고있다. 나 또한 그동안 스프링 시큐리티를 가볍게만 사용해보았고, 여러가지 지원되는 기술들을 면밀하게 장단점을 알고 쓰질 못했다. 스프링 진영에서 인증, 권한을 포함한 보안과 관련된 프레임워크는 단연 시큐리티 만한게 없다고 생각해왔고, 평판도 익히 들었다. 그동안 미루어왔던 시큐리티 학습을 시작해보려고 한다. 아래 책을 따라가면서, 실습을 해 볼 예정이다. 책의 버전과 현재 버전이 일치하지 않는 부분도 있고, 그냥 내가 만들고 싶은걸 만들면서 배우고 싶은 생각도 있어서 예제를 그대로 따라가지 않고 시큐리티를 실습해 볼 예정이다. http://www.acornpub.co.kr/book/spring-security-3e 우선, 책 첫 부분에 나오는 초기 세팅 및 inMemoryAuthentication 의 예제이다. spring boot 버전은 2.3.0.RELEASE 이며, spring security 버전은 5.3.2.RELEASE 이다. 아래에서 확인이 가능하다. MVC 구조에서 간단하게 진행하기 때문에, web 을 추가했고 또한 thymeleaf 템플릿 엔진을 사용할 것이다. jpa 와 h2 는 추후에 jdbc 기반 인증을 하기 위해서 미리 넣어두었다. lombok 과 devtools 는 애용하기 때문에 집어넣었다. 그렇다면, 본론으로 넘어가서 Security 설정을 해보자. WebSecurityConfigurerAdapter 를 상속 받아 configure 메서드를 재정의하면 된다. configure(AuthenticationManagerBulider) 메서드에서 AuthenticationManagerBuilder 객체는 스프링 시큐리티가 사용자를 인증하는 방법을 설정한다. 아래의 경우, 인메모리 데이터 저장소를 이용해 사용자명과 패스워드를 비교한다. 인메모리 데이터 저장소에 2개의 2개의 계정을 물고 있으며, 해당 2개의 계정만...

DDD(Domain Driven Design) - Domain, BC (Bounded Context), Context Mapping, Ubiquitous Language

이미지
프로젝트가 진행됨에 따라, 서비스 혹은 회사가 성장함에 따라 요구사항은 다양해지고 기존의 시스템에도 변경이 일어난다. 이는 불가피하게 시스템의 복잡성을 증가를 수반하게 된다. 따라서, 시간이 지날수록 클린 코드와 클린 아키텍쳐를 이룰 수 없게 될지 모른다. 이를 Software Entropy 라고 부른다. https://www.webopedia.com/TERM/S/software_entropy.html 시스템에 수많은 변경과 반영이 일어나면서, 적절한 관심사 분리와 클래스와 모듈간의 결합도를 낮추는것을 유지하는것은 점점 더 어려워 지며, 아키텍쳐 레벨에서 가이드라인을 강제하지 않을 경우 시스템의 새로운 기능 및 변경이 더이상 힘들어질 수 있다. 전통적인 MVC (Model-View-Controller) 아키텍쳐에선, "M" Layer 는 모든 비즈니스 로직을 가지고 있다. 그러나 MVC 에서에는 깔끔하고 적절하게 책임의 경계를 이루기 어렵다. 몇가지 패턴들은 해당 문제를 완화시킬 수 있지만, 여전히 로직과 책임이 새어나갈 여지가 있다. 반대로, 비즈니스 전문가들과 요구 사항을 수집하고, 기술적인 팀과 비기술적인 팀 사이에서 합의점을 찾아는 과정에서, 시스템을 설계하고 수행할 때 양측은 서로 자신의 부분에 맞게 잘못 해석할 여지가 있다. 결과적으로 이는 원래의 목표와는 다르게 프로젝트에 반영될 여지가 충분하다. 그리고, 변수와 클래스 메서드 등을 네이밍할 때 개발자들이 가장 힘들어 하는 부분이다. 우리는 다른 개발자가 명확하게 코드에서 작성자의 의도를 이해할수 있도록 해야하며, 또한 비즈니스 관계자(기획자, 테스터 등)들 및 이해관계자들과 의사소통을 할 때도 충분하게 활용할 수 있어야한다. DDD 는 소프트웨어 프로젝트에서 충돌하는 기술팀과 비기술팀을 조정하면서 동시에 성공적인 시스템 구축을 쉽게하는 기술들과 패턴을 제안하며 기존의 문제들을 해결할 수 있다. DDD 란 무엇인가 ? 먼저 Domain 이 무엇인지 알...

DDD(Domain Driven Design) - Aggregate (어그리게잇)

이미지
DDD 에서 중요한 개념인 Entity 와 Value Object 에 대해서 다른 글들에서 알아봤다. 하지만 이외에도 가장 중요한 개념이 아마 Aggregate 가 아닌가 생각한다. 그렇다면 Aggregate ( 애그리게잇 ) 이란 과연 무엇인가 ??! 어그리게잇은 Entity 와 Value Object 들의 집합이며, 함께 클러스터링 되어 트랜잭션의 경계를 이룬다. 어그리게잇자체도 Entity 이기에 mutability 를 가지고 있다. 또한 Invariants 를 가진다. 비즈니스 상으로 필수적으로 일관성을 지켜야하는 룰이 있다. 예를 들어 Order 라는 주문 애그리게잇은 주문하려는 상품의 재고가 0일 경우 주문이 이루어 질 수 없다. 이는 Order 라는 애그리게잇의 생성과 관련된 필수적으로 일관성을 지켜야하는 룰이다. Aggregate 를 설계할 때 주의해야 할 점을 다루어보겠다. 크기가 큰 Aggregate 는 좋은가? -> 좋지 않다. Aggregate 는 Entity 이면서 동시에 다른 Entity 를 가질 수 있다. 이는 생애주기를 가지는 객체라는 말을 의미하게 되는데, 크키가 커질수록 당연히 클러스터링 되는 Entity 또한 증가할 것이다. 따라서 Entity 가 커질수록 트랜잭션을 다루기 어려워지며, 트래픽이 증가할 수록 동시성 이슈도 고려를 해야한다. 동시성 이슈는 DDD 에서는 Version 을 통해 Optimistic Locking 기법을 보통 사용한다. Pessimistic Locking 의 경우 Database level 에서 컨트롤하기 때문에 이는 Domain 에 기반한 접근과 거리가 있다. 진짜 고정자를 일관성 경계 안에 모델링하라 -> 고정자는 앞서 언급했듯이, 언제나 일관성을 유지해야만 하는 비즈니스 규칙이다. 일관성에는 아래와 같이 두 가지를 다룰 수 있다. 트랜잭션적 일관성 ( Transactional consistency ) 결과적 일관성 ...

DDD(Domain Driven Design) - Value Object (값 객체)

이미지
이번에 다룰 DDD 의 내용은 바로 값 객체이다. 반 버논에 도메인 주도 설계 구현에서는 되도록이면 엔터티가 아니라 값 객체를 사용해 모델링하도록 노력해야 한다고 말한다. 값 객체의 이점으로 책에서는 아래와 같이 언급한다. "측정하고 수량화하거나 설명해주는 값 타입은 생성, 테스트, 사용, 최적화, 유지 관리가 더 쉽다." 그렇다면  도메인 개념을 값으로 모델링해야 할지 알 수 있는 방법은 무엇인가? 아래와 같은 특징을 포함하는지 고려해야 한다. 도메인 내의 어떤 대상을 측정하고, 수량화하고, 설명한다. 불변성이 유지될 수 있다. 관련 특성을 모은 필수 단위로 개념적 전체를 모델링한다. 측정이나 설명이 변경될 땐 완벽히 대체 가능하다. 다른 값과 등가성(value equality) 을 사용해 비교할 수 있다. 협력자(collaborator) 에게 부작요이 없는 행동 (Side-Effect-Free Behavior) 을 제공한다. 측정, 수량화, 설명 -> 도메인 내에 있는 어떤 대상을 측정하고 수량화하고 설명하는 개념. ex) 사람에겐 나이가 있다. 나이는 실재하는 어떤 대상은 아니지만, 사람이 살아온 햇수를 측정하거나 수량화 한다. 불변성 -> 값 객체는 한 번 생성되면 변경할 수 없다. 보통 java 에서 객체를 생성할 때 특정 생성자 혹은 팩토리 패턴을 이용해서 생성후 객체의 변경을 할 수 있는 메서드를 제공하지 않는 방법으로 불변성을 유지할 수 있다. 만약 지금 설계하고 있는 객체가 자신의 행동으로 인해 변경돼야 한다고 생각한다면, 이는 값 객체가 아니라 엔터티로 설계해야 함을 의미한다. 개념적 전체 (Conceptual Whole) -> 값 객체는 하나 이상의 개별적 특성을 가질 수 있으며, 각 특성은 서로 연관되어 있다. 여러 특성이 설명하는 바를 모아 전체를 나타낸다.  ex) {50,000,000달러} 는 50,000,000 이라는 특성과 달러...

DDD(Domain Driven Design) - Entity (엔터티)

이미지
DDD 를 알기전에는 나역시 그랬고, 반 버논의 도메인 주도 설계 구현에서도 언급한 내용이 있다. 바로 "개발자는 도메인보다 데이터에 초점을 맞추려는 경향이 있다." 소프트웨어 개발에 관한 대부분의 접근법이 데이터베이스에 중점을 두기 때문에, DDD를 처음 접하는 사람에게 일어날 수 있는 현상이라고 한다. 나도 매우 동의한다. 지금까지 그렇게 해왔다. 풍부한 행동을 바탕으로 도메인 개념을 설계하지 않고, 데이터의 속성(컬럼)과 연결(외래 키)을 먼저 생각하려 한다. 이를 바탕으로 데이터 모델을 대응하는 객체로 투영하게 되는데, 이로 인해 게터와 세터로 가득찬 무기력한 도메인이 되버린다. 지금부터 엔터티란 무엇인가에 대해서 다루어 보려고한다. 1. 엔터티는 식별자 를 가진다. 2. 엔터티는 변화 가능성(mutability) 을 가진다. -> 엔터티는 고유한 대상으로 긴 시간에 걸쳐 계속해서 변화한다. 어떤 예를 들 수 있을까? 지금 재직 중인 회사에서 엔터티로 다룰 수 있다면, 제일 먼저 생각나는 엔터티는 Order(주문) 이다. 특정 식별자를 가진 주문의 상태는 계속해서 변화한다. 객체를 특성(attribute) 이 아니라 식별자에 따라 구분한다면, 모델을 정의할 때 이를 우선적으로 다루어야 한다고 한다. 클래스의 정의를 단순하게 유지하면서 수명주기의 지속성(continuity)과 식별자에 집중해야 한다고 한다. 형태나 히스토리에 상관없이, 각 객체를 구분하는 수단을 정의해야 한다고 한다. 이 모델에선 같은 대상이 된다(아마도 equals and hashcode 를 의미하는 것 같다)는 의미가 무엇인지 반드시 정의해야 함을 강조하고 있다. 앞서, 엔터티는 식별자를 가지고 변화 가능성을 가진다고 했다. 따라서 시간이 흘러도 고유성(uniqueness) 을 보장할 수 있도록, 식별자를 구현하는 방법들을 확보하는 것이 중요하다. 그렇다면, 식별자를 구현하는 방법에는 어떤것들이 있을까? 1. 사용자가 식별자를...

DDD(Domain Driven Design) - Repository 리파지토리

이미지
반 버논의 도메인 주도 설계 구현 이라는 책을 완독하고 나서 여러가지 정리할 점들이 있는데, 그 중 하나가 레포지토리 이다. 오늘은 리파지토리에 대해서 다루어 보려고 한다. 지금 재직중인 회사나 전회사에서 일할때도 Database 중심적 설계를 바탕으로 시스템을 구축했다. 그리고 내가 가보지 못한 대부분의 회사들도 아마도 DDD 를 실무에서 적용하고 있지 않을 것이라고 감히 추측해 본다. 물론 DDD 를 실질적으로 도입하고 있는 회사도 많을 것이다. 잡소리는 그만하고, 리파지토리에 대해서 다루어 보겠다. 반 버논의 도메인 주도 설계 구현에서 리파지토리에 아래와 같이 2 가지를 다루고 있다. - 컬렉션 지향 리파지토리 ( collection-oriented-repository ) - 영속성 지향 리파지토리 ( persistence-oriented-repository ) 먼저, 컬렉션 지향 리파지토리이다. 책에서는, 컬렉션 지향 리파지토리는 Set 컬렉션을 흉내 내야 한다고 한다. 이 말이 무슨 말이냐면, Set에 있는 같은 객체(equals and hashcode)의 인스턴스는 두 번 추가되로록 허용해서는 안 된다. 또한 리파지토리로부터 객체를 가져오게 하고 수정할 때 이를 리파지토리에 "재저장" 할 필요가 없다. 이를 단순하게 이해하기 위해서, 책에서 나온 예제를 살펴보겠다. 표준 java.util.HashSet 을 확장하고 고유 식별자로 특정 객체를 찾도록 해주는 새로운 타입상의 메서드를 생성한다고 한다. 확장 클래스로 CalendarRepository 라는 이름을 주어 인식할 수 있도록 해주었다. 하지만 이는 단순한 인메모리 HashSet 이다. 리파지토리에서 find 를 통해서 찾은 객체를 수정한 뒤, 명시적으로 다시 add 해주지 않는다. 수정내역은 해당 객체에서 바로 일어나기 때문이다. 이와 관련된 예제로 직접 작성해보았다. 아래에서 확인할 수 있듯이, me 라는 User 타입의 객체의 n...

Vanilla JS - select tag with namedItem

이미지
최근에 레거시를 유지 보수하면서, JS 및 JQuery 를 만지는 일이 있었다. 일을 하면서 select 태그의 option 태그를 selected 가 아닌, 특정 value 값을 기준으로 option 태그를 선택 후 해당 텍스트값을 가져와야 하는 작업이 필요했었다. 보통 select 태그를 사용하게 되면, selected 인 option 의 value 혹은 text 값을 핸들링 하는데, 해당 케이스는 보통 케이스와 달라서 아주 잠깐 당황했었다. 해결법은 물론 있다. 레거시를 만지면서, JQuery 를 최대한 걷어내고 있는데, JQuery 선택자를 이용하면 매우 간단하게 해결할 수 있다. 예를 들어, 아래와 같이 한 줄 이면 간단하게 해결이 가능하다. 근데, 요즘 JQuery 를 사용하지 않는데 이점이 더 큰것을 알아가고 있어서 JQuery 를 사용하지 않기로 결심했다. 따라서 namedItem 이라는 method 를 사용해보았다. https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/namedItem The  HTMLSelectElement.namedItem()  method returns the  HTMLOptionElement  corresponding to the  HTMLOptionElement  whose  name  or  id  match the specified name, or  null  if no option matches. name 혹은 id 속성을 이용해서 Element 를 선택한다. 아래에서 확인할 수 있듯이, Edge 와 IE 에서는 name 속성이 지원이 안된다고 한다. 따라서 id 속성을 이용하는것이 크로스 브라우징에 매우 유리하다. 그럼 우선 예제를 보자, 아래와 같이 fruits 라는 id 속성을 가진 sele...