[데브코스] Spring Security - 5
Updated: Categories: TILW16D4 - log4jdbc / Spring Security - JDBC 연동에 대해 알아보자
log4jdbc-remix
- 실행되는 SQL 및 ResultSet을 로깅해주는 라이브러리
BeanPostProcessor
인터페이스를 구현하여, DataSource 객체를Log4jdbcProxyDataSource
타입으로 Wrapping 처리
DataSourcePostProcessor
@Component
public class DataSourcePostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource && !(bean instanceof Log4jdbcProxyDataSource)) {
return new Log4jdbcProxyDataSource((DataSource) bean);
} else {
return bean;
}
}
}
- logback 설정을 통해 선택적으로 로깅 처리
logback.xml
<logger name="jdbc.sqltiming" level="INFO"/>
<logger name="jdbc.resultsettable" level="INFO"/>
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.connection" level="OFF"/>
<logger name="jdbc.sqlonly" level="OFF"/>
- 아래처럼
sqltiming
과resultsettable
설정이 잘 뜨는걸 볼 수 있다!
JDBC와 연동
- 사용자를 인증할때
UserDetailsService
인터페이스를 사용하게 된다. - 구현체 중 JDBC를 지원하는
JdbcDaoImpl
클래스를 사용하면 인증과정을 DB와 연동할 수 있음- 단 반드시 테이블이 다음과 같은 구조를 가져야함.
CREATE TABLE users
(
username varchar(20) NOT NULL,
password varchar(80) NOT NULL,
enabled varchar(20) NOT NULL DEFAULT false,
PRIMARY KEY (username)
);
CREATE TABLE authorities
(
username varchar(20) NOT NULL,
authority varchar(20) NOT NULL,
PRIMARY KEY (username)
);
- 이제 DataSource를
UserDetailsService
를 통해 연동해주면 된다
WebSecurityConfig 클래스
@Bean
public UserDetailsService userDetailsService(DataSource dataSource) {
JdbcDaoImpl jdbcDao = new JdbcDaoImpl();
jdbcDao.setDataSource(dataSource);
return jdbcDao;
}
UserDetailsService
의JdbcDaoImpl
구현체에 DB를 연동해주고 빈으로 띄워준다
Permission & Group
- 사용자와 권한 사이에 그룹이라는 간접 계층을 둘 수 있음
- 사용자는 특정 그룹에 속하게 되고, 그룹은 권한 집합을 참조함
- 즉, 사용자를 특정 그룹에 속하게 함으로써, 그룹에 속한 권한을 일괄 적용할 수 있음
- 위와 같은 의존 관계를 적용해주기 위해선
JdbcDaoImpl
의 기본 쿼리를 바꿔줘야 한다.usersByUsernameQuery
: username으로 해당 유저를 찾는다groupAuthoritiesByUsernameQuery
: username으로 그룹 권한을 가져온다.
@Bean
public UserDetailsService userDetailsService(DataSource dataSource) {
JdbcDaoImpl jdbcDao = new JdbcDaoImpl();
jdbcDao.setDataSource(dataSource);
jdbcDao.setUsersByUsernameQuery(
"SELECT login_id, passwd, true FROM USERS WHERE login_id = ?"
);
jdbcDao.setGroupAuthoritiesByUsernameQuery(
"SELECT " +
"u.login_id, g.name, p.name " +
"FROM " +
"users u JOIN groups g ON u.group_id = g.id " +
"LEFT JOIN group_permission gp ON g.id = gp.group_id " +
"JOIN permissions p ON p.id = gp.permission_id " +
"WHERE " +
"u.login_id = ?"
);
jdbcDao.setEnableAuthorities(false);
jdbcDao.setEnableGroups(true);
return jdbcDao;
}
- 하지만 이렇게
UserDetailsService
를 커스텀하여 적용하는 것은 정석적인 방법이 아니다!!- RememberMe 인증에서 Exception이 발생하게 됨.
- 따라서 아래와 같이
AuthenticationManagerBuilder
를 사용해JdbcDaoImpl
클래스를 커스텀해줄 수 있다.
WebSecurityConfig 클래스
private DataSource dataSource;
@Autowired
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"SELECT login_id, passwd, true FROM USERS WHERE login_id = ?"
)
.groupAuthoritiesByUsername(
"SELECT " +
"u.login_id, g.name, p.name " +
"FROM " +
"users u JOIN groups g ON u.group_id = g.id " +
"LEFT JOIN group_permission gp ON g.id = gp.group_id " +
"JOIN permissions p ON p.id = gp.permission_id " +
"WHERE " +
"u.login_id = ?"
)
.getUserDetailsService()
.setEnableAuthorities(false)
;
}