현재 회사에서 스프링 부트 프로젝트를 자바로 진행하고 있는데, 이 프로젝트가 끝나면 이후 프로젝트는 코틀린으로 진행해볼까 한다.
그러기에 앞서 코틀린을 공부를 해야하는데, 코틀린을 곁들인(?) 스프링 부트로 간단히 백오피스 같은 느낌으로 개발 체크리스트 토이프로젝트를 만들어보고 싶어졌다.
초기 프로젝트를 생성하는데에 있어서 JPA 와 H2 까지는 문제가 없었는데, 시큐리티를 적용함에 있어서 발생한 문제가 몇 있어서 이를 메모차 기록해두려고 한다.
본 포스트는 스프링 부트 프로젝트 초기 생성 시 Spring JPA, Spring Security, H2 Database 를 포함하여 만들었다고 가정하고 Gradle 또는 Maven 에 의존성을 설치하는 과정은 생략한다.
h2:
console:
enabled: true # 콘솔을 enable 해야 H2 콘솔에 접근할 수 있다.
datasource:
driver-class-name: org.h2.Driver # H2 드라이버 지정
url: jdbc:h2:mem:dchecklist;MODE=MySQL # Scheme 은 dchekclist 로, 에뮬레이트 방식은 MySQL 로 지정
username: root # 사용할 아이디
password: password # 사용할 패스워드
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
format_sql: true
show-sql: true
generate-ddl: true
database-platform: org.hibernate.dialect.MySQL8Dialect # 로그에 출력되는 쿼리 형식은 MySQL8 기준
여기서 url
키에서 jdbc:h2:mem:dchecklist;MODE=MySQL
을 지정해주었는데, 여기서 MODE 는 공식 도큐먼트에 따르면 H2 는 다른 데이터베이스의 동작 방식을 일부분 에뮬레이팅 할 수 있다고 한다.
즉, H2 를 사용하고 있긴 하지만, 데이터베이스가 동작하는 방식은 마치 MySQL 인 것 처럼 사용할 수 있다는 것이다.
For certain features, this database can emulate the behavior of specific databases. However, only a small subset of the differences between databases are implemented in this way.
이 상태로 스프링 부트 서버를 실행시키고, /h2-console
로 접근해보자.
스프링 시큐리티에 걸려서 기본 Form Login 화면이 나온다. 그럼 시큐리티에서 Form Login 을 해제해보자.
Config 를 설정하기 위해 SecurityConfig.kt 파일을 생성하였다.
// SecurityConfig.kt
@EnableWebSecurity
class SecurityConfig {
@Bean
fun security(http: HttpSecurity): SecurityFilterChain {
// formLogin 해제
http.formLogin().disable();
return http.build();
}
}
사담이지만, 기존 스프링 시큐리티를 설정하기 위해서는 WebSecurityConfigurerAdapter
를 상속받고, configure
메소드를 오버라이딩했었지만, 공식 도큐먼트에 따르면 시큐리티 5.7.0 버전부터는 해당 어댑터가 Deprecated 되었다고 한다. 그 대신 SecurityFilterChain
를 Bean 으로 등록하여 사용하라고 권고한다.
In Spring Security 5.7.0-M2 we deprecated the WebSecurityConfigurerAdapter, as we encourage users to move towards a component-based security configuration.
이와 관련된 자세한 이야기는 나중에 시간이 되면 따로 포스팅해보면 좋을 것 같다.
아무튼, 본론으로 다시 돌아와서 서버를 다시 실행시켜본다.
폼 자체는 잘 나온다. 이제 여기서 JDBC URL
의 경로를 적절히 잘 입력해주고, User Name
과 Password
입력 폼을 작성하고 Connect 를 눌러주자.
오.. 403 에러가 발생한다. Forbidden 이다. 즉, 접근 권한이 없어서 발생한다. 스프링 시큐리티가 아예 차단해버리는 것으로 보인다.
그렇다면 시큐리티 단에서 /h2-console
엔드포인트를 허용해주면 될 것 같다.
// 생략
@Bean
fun security(http: HttpSecurity): SecurityFilterChain {
// ...생략
// h2-console 은 모두 허가
http.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
return http.build();
}
// 생략
다시 실행시켜본다.
..? 아니 동일한 오류다.. 무엇이 문제일까 싶어 CSRF 를 Disable 해주었다.
// 생략
@Bean
fun security(http: HttpSecurity): SecurityFilterChain {
// ...생략
// CSRF 해제
http.csrf().disable();
return http.build();
}
// 생략
참고로, 내가 만들 프로젝트는 RestAPI 로서, 인증 방식은 JWT 를 사용할 것이기 때문에 CSRF 로부터 자유롭다고 판단되어 disable 시켜주었다.
3년 전 스택오버플로우 글이긴 하지만, 참고용으로 관련 스택오버플로우 링크를 걸어둔다.
아무튼 다시 실행시켜본다.
오.. 이번에는 X-Frame-Option
관련한 오류가 나온다. 그래서 개발자 도구를 통해 DOM 을 살펴보았다.
frameset
태그를 사용한 것으로 보이는데, 검색해보니 각기 다른 HTML 파일을 불러와서 화면을 구성하는 방식이라고 한다. 이때 스프링 시큐리티에서는 기본적으로 X-Frame-Option
이 차단되어있다고 한다.
그렇다면 이번에 처리해야할 것은 감이 오는데, 그렇다고 모든 X-Frame-Option 에 대해서 disable()
처리를 할 것인지, 아니면 동일한 Origin 만 허용하는 sameOrigin()
정책을 적용할 것인지는 판단에 따라 다를 것 같다.
나는 sameOrigin()
을 택했다..
// .. 생략
@Bean
fun security(http: HttpSecurity): SecurityFilterChain {
// ... 생략
// X-Frame-Option 허용
http.headers()
.frameOptions()
.sameOrigin().and();
return http.build();
}
// 생략..
이제 실행시켜보자.
드디어 잘 나온다. TB_EXAMPLE
테이블에 대해서도 데이터가 잘 나온다.
끗.