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개의 계정만 인증이 가능한 상황을 만든다.


- 아이디 : john@ndgndg91.com 비밀번호 : john-ndgndg91 권한 : USER
- 아이디 : admin 비밀번호 : admin 권한 : ADMIN

configure(HttpSecurity) 메서드에서 HttpSecurity 객체는 현재 로그인한 사용자가 적절한 역할과 연결되어 있는지 확인하는 서블릿 필터를 생성한다.

loginPage() 메서드는 보호된 페이지에 임의의 사용자나 인증되지 않은 사용자가 접근하는 경우, 스프링 시큐리티가 리다이렉션할 위치를 지정한다. default 값은 /spring_security_login 로 DefaultLoginPageGeneratingFilter 가 처리하도록 설정되어 있고, o.s.s.web.filter.FilterChainProxy 는 o.s.s.web.authentication.ui.DefaultLoginPageGeneratingFilter 를 선택해 위임자 중 하나로 기본 로그인 페이지를 렌더링 한다. 내가 만든 예제에서는 /login/form 으로 리다이렉팅 되고 해당 페이지를 렌더링한다.

loginProcessUrl() 메서드의 default 값은 /j_spring_security_check 이다. 해당 메서드에 지정한 path 는 HTTP POST 로 매개변수( 사용자명과 패스워드 ) 가 전달 되며 로그인 시도하는 path 이다.

failureUrl() 메서드는 loginProcessUrl() 을 통해 제출한 사용자명과 패스워드가 잘못된 경우, 리다이렉션할 path 를 지정한다.

username()passwordParameter() 메서드의 기본값은 각각 j_usernamej_password 이며, loginProcessUrl() 메서드를 처리할 때 사용자를 인증하는 데 사용할 HTTP POST 매개변수를 지정한다.

logoutUrl() 메서드는 로그아웃을 가리키는 path 이다. default 값은 /j_spring_security_logout 이다.

logoutSuccessUrl() 메서드는 로그아웃이 정상적으로 이루어지고 리다이렉션할 path 를 지정한다.

antMatchers() 메서드의 경우 path 에 따라 지정한 권한을 가진 사용자에게 접근을 허용하도록 지정한다. 해당 메서드를 작성할 때 순서에 매우 주의해야한다. 위에서 부터 순차적으로 적용되기 때문이다.

아래의 예시를 확인하면, 모든 요청은 모든 사용자에게 허용된다는 것이 맨처음 나온다. 그뒤에 /admin/ 으로 시작되는 path 는 ADMIN 권한을 가진 사용자만 접근이 가능하다는 내용인데, 해당 내용은 오류도 나지 않고 적용도 되지 않는다. 이는 개발자에게 블랙홀과 같다. 분명히 오류는 안나는데, 적용은 안되기 때문에 상당히 주의해서 작성해야 한다.

그렇다면, 간단하게 ant 패턴을 익혀보자.

  • "/events/**" 패턴은 "/events", "/evnets/", "/events/1", "/events/1/form?test=1" 와 일치한다. 하지만, "/event123" 과 일치하지 않는다.
  • "/events*" 패턴은 "/events", "/events123" 과 일치한다. 하지만, "/events/" 또는 "/events/1" 과 일치하지 않는다.
  • "/events*/**" 패턴은 "/events", "/events/", "/events/1", "/events123", "/events123/456", "/events/1/form?test=1" 모두 일치한다.





비밀번호에 {noop} 를 붙인 이유는 spring security 5 부터 NoOpPasswordEncoder 가 Deprecated 되었다. {noop} 문자열을 붙이지 않는다면, passwordEncoder 를 등록해줘야 한다.

아니면 아래와 같이 상콤한 예외를 만나게 된다.


아래는 사용자들의 권한을 enum 으로 관리한다.

아래는 login page 를 렌더링 해주는 역할이다.

아래는 login.html 의 내용이다. form 에 아까 지정했던 loginProcessUrl 로 /login 과 맞춰준다. 그리고 method 는 POST 이다.
param.error 가 있는 경우 인증에 실패했다는 것이며, param.logout 이 있는 경우 정상적으로 로그아웃 처리가 된 후 리다이렉션 되었다는 의미이다. 따라서 각각의 문구를 띄워준다.



자, 그렇다면 간단하게 실행 스크린샷
http://127.0.0.1:8080 을 접속하게 되면,
.antMatchers("/").hasAnyRole(Role.USER.name(), Role.ADMIN.name()) 에 따라
권한을 체킹한다. 당연히 권한이 없기 때문에, 아까 지정한
.loginPage("/login/form") path 로 리다이렉션 되며, login.html 을 렌더링하게 된다.
아래의 모습이다.

그렇다면, 아까 인메모리 저장소에 등록해놓은 admin/admin 을 입력하기전에 admin/1 로 일부러 인증에 실패해보자.
그렇다면, 당연히 인증에 실패하게 되고 query string 에 error 가 보이는가?
빨간 메세지가 출력된다.

그렇다면, 이제 admin/admin 으로 로그인 해보자. 아래와 같이 "/" 기본 path 인 index.html 로 접근이 되었다. 그렇다면 이제 myCalendar 옆에 log-out 을 클릭해보자.
정상적으로 로그아웃이 되었고, /login/form?logout 으로 리다이렉션 되었다.
query string 에 logout 이 있기 때문에 메세지가 출력되었다.

내가 준비한 예제는 여기까지이고, 책을 따라서 더 공부하고 나만의 예제를 만든다음에,
다시 블로깅하겠다.

아래는 내가만든 예제 github 주소이다.

댓글

이 블로그의 인기 게시물

About JVM Warm up

About idempotent

About Kafka Basic

About ZGC

sneak peek jitpack

Spring Boot Actuator readiness, liveness probes on k8s

About Websocket minimize data size and data transfer cost on cloud

About G1 GC

대학생 코딩 과제 대행 java, python, oracle 네 번째