스프링 시큐리티 ③ : 사용자 저장소
사용자 저장소에는 요청별로 요구하는 권한과 사용자 정보가 저장되어있어야한다. 두 가지 방법으로 이 사용자 저장소를 지정하고, 저장소에 있는 사용자를 권한처리 할 수 있다.
1. 인 메모리
서버의 메모리 내부에 사용자 저장소를 만드는 방식이다. 계정의 종류가 매우 적고, 계정의 아이디, 패스워드, 권한목록이 변경되지 않을때 사용하기 좋다. configure() 메서드를 아래와 같이 오버라이드해 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() // 인메모리 사용자 저장소 활성화 .withUser("user").password("password").roles("USER") .and() .withUser("admin").password("password").roles("USER", "ADMIN"); } } | cs |
위 설정대로 인메모리 사용자 저장소를 만들었다면, 접속 계정은 user 와 admin 두 종류가 된다. 각각의 계정의 패스워드는 password() 내부 파라미터 값이고, 계정이 가지고 있는 권한은 roles() 내부 파라미터들이다. user 계정은 USER 권한을, admin 계정은 USER와 ADMIN 권한을 가지게된다.
여기에 추가적으로, 아래 목록에 있는 메서드를 이용해 좀 더 상세한 설정이 가능하다.
메서드 |
설명 |
accountExpired(boolean) |
계정이 만료되었는지 아닌지를 정의 |
accountLocked(boolean) |
계정이 잠겨있는지 아닌지를 정의 |
and() |
설정을 연결하기 위해 사용 |
authorities(GrantedAuthority …) |
사용자에게 부여된 권한들을 명시 |
authorities(List<? extends GrantAuthority>) |
사용자에게 부여된 권한들을 명시 |
authorities(String …) |
사용자에게 부여된 권한들을 명시 |
credentialsExpired(boolean) |
자격이 만료되었는지 아닌지를 정의 |
disabled(boolean) |
계정이 비활성화 되었는지 아닌지를 정의 |
roles(String …) |
사용자에게 부여된 역할을 명시 |
2. 데이터 베이스
JDBC를 이용해 사용자 저장소를 만드는 방식이다. 스프링 시큐리티에서 JDBC 지원 사용자 저장소를 통해 인증을 하기 위해서 jdbcAuthentication() 메서드를 사용한다.
1 2 3 4 5 6 7 8 | @Autowired DataSource dataSource; @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource); } | cs |
위 코드처럼 기본적인 설정시 스프링 시큐리티 내부에서 사용자 정보를 검색하는 SQL 쿼리를 실행한다.
만약, 스프링 시큐리티에서 기본적으로 지정된 테이블과 다를경우에는 추가적인 제어가 필요하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Autowired DataSource dataSource; @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery( "SELECT USERNAME, PASSWORD, TRUE " + "FROM CUSTOM_TABLE " + "WHERE USERNAME = ?") .authoritiesByUsernameQuery("SELECT USERNAME, 'ROLE_USER' FROM CUSTOM_TABLE WHERE USERNAME = ?"); } | cs |
이 때, 반드시 지켜야할 규칙이 있다. 모든 쿼리의 사용자명(USERNAME)은 유일한 인자(키)이어야 한다.
인증 쿼리에서는 사용자명과 암화 활성화 여부를 선택하고, 권한 쿼리에서는 사용자명과 부여받은 권한을 선택한다.
사용자의 암호는 보통 암호화 해서 저장을 할 텐데, 사용자에게서 입력받은 텍스트는 평문이기 때문에 절대로 일치할 수 없을 것이다.
이 문제를 해결하기 위해 passwordEncoder() 메서드를 사용하는데 아래와 같이 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Autowired DataSource dataSource; @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery( "SELECT USERNAME, PASSWORD, TRUE " + "FROM CUSTOM_TABLE " + "WHERE USERNAME = ?") .authoritiesByUsernameQuery("SELECT USERNAME, 'ROLE_USER' FROM CUSTOM_TABLE WHERE USERNAME = ?") .passwordEncoder(new StandardPasswordEncoder("keykey")); } | cs |
StandardPasswordEncoder가 맘에 들지 않는다면 PasswordEncoder를 구현한 클래스를 만들어 대체하면된다!
|
이 포스트는 스프링 인 액션을 읽고 개인적으로 필요하다고 생각되는 내용을 정리한 포스트입니다. 일부 내용, 소스코드는 스프링 인 액션의 내용일 수 있습니다. |
'🌱 SPRING > 스프링 인 액션' 카테고리의 다른 글
스프링 시큐리티 ② : 상세 설정하기 (0) | 2018.09.16 |
---|---|
스프링 시큐리티 ① : 기본 설정 (0) | 2018.08.01 |
예외 처리하기 (0) | 2018.07.31 |
멀티 파트 폼 데이터 (0) | 2018.06.13 |
자바 설정으로 Filter 등록하기 (0) | 2018.06.13 |