DBILITY

spring boot security mybatis 본문

java/spring cloud

spring boot security mybatis

DBILITY 2019. 9. 23. 16:07
반응형

연동하는데 주력했다.

먼저 dependancy를 추가한다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
</dependency>
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.1.0</version>
</dependency>

application.properties에 db설정 등 처리

#mem base
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=- 1;DB_CLOSE_ON_EXIT=FALSE
#file base
#spring.datasource.url=jdbc:h2:file:/data/testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.datasource.initialization-mode=always

spring.datasource.schema=classpath*:schema.sql
spring.datasource.data=classpath*:data.sql

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

#mybatis.config-location=classpath:mybatis/config/mybatis-config.xml
#mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

logging.level.com.dbility=debug
logging.level.org.springframework.jdbc=debug
logging.level.org.springframework.security=debug
logging.level.org.mybatis=debug
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-7level %50.50logger{36} %4.4L - %msg%n%ex{full, DISPLAY_EX_EVAL}

 

schema.sql

CREATE TABLE IF NOT EXISTS Member (
	username VARCHAR(20) NOT NULL,
	password VARCHAR(255) NOT NULL,
	enabled BOOLEAN NOT NULL,
	PRIMARY KEY(username)
);

CREATE TABLE IF NOT EXISTS Role (
	username VARCHAR(20) NOT NULL,
	authority VARCHAR(20) NOT NULL,
	FOREIGN KEY(username) REFERENCES Member(username)
);

data.sql

INSERT INTO Member VALUES ('master','{bcrypt}$2a$10$MPuZy36Gzf9awY7czwUWAOAJmDZ1EA6tIsJEf6p/XHuzt8R532pSm',1);
INSERT INTO Member VALUES ('clerk','{noop}1234',1);

INSERT INTO Role VALUES ('master','ADMIN');
INSERT INTO Role VALUES ('master','USER');
INSERT INTO Role VALUES ('clerk','USER');

mybatis-configuration file

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <settings>
  	<setting name="useGeneratedKeys" value="true"/>
  	<setting name="jdbcTypeForNull" value="VARCHAR"/>
  	<setting name="mapUnderscoreToCamelCase" value="true"/>
  	<setting name="callSettersOnNulls" value="true"/>
  </settings>

  <mappers>
    <mapper resource="mybatis/mapper/empty_mapper.xml"/>
  </mappers>
</configuration>

 

empty_mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mybatis.mapper.empty_mapper" />

member_h2.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="member">

	<select id="selectMember" parameterType="string" resultType="hashmap">
	<![CDATA[
		SELECT username,password,enabled FROM Member WHERE username=#{username}
	]]>
	</select>

</mapper>

role_h2.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="role">

	<select id="selectListRole" parameterType="string" resultType="string">
	<![CDATA[
		SELECT authority FROM Role WHERE username=#{username}
	]]>
	</select>

</mapper>

mybatis spring configuration

package com.dbility.spring.cloud.security.config;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SqlSessionConfiguration {

	@Autowired
	private DataSource dataSource;

	@Autowired
	private ApplicationContext applicationContext;

	@Bean
	public SqlSessionFactory sqlSessionFactory () throws Exception {
		final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		sessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/config/mybatis-config.xml"));
		sessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/mapper/*.xml"));
		return sessionFactoryBean.getObject();
	}

	@Bean
	public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
		final SqlSessionTemplate sqlSessionTemple = new SqlSessionTemplate(sqlSessionFactory);
		return sqlSessionTemple;
	}
}

 

Repository용 Dao작성

Dao.java interface

package com.dbility.spring.cloud.security.dao;

import java.util.HashMap;
import java.util.List;

public interface Dao<T> {

	public List<T> selectList(String sqlId, HashMap<String,Object> map) throws Exception;
	public List<T> selectList(String sqlId, String username) throws Exception;
	public T selectOne(String sqlId, String username) throws Exception;

}

DaoImpl.java

package com.dbility.spring.cloud.security.dao;

import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class DaoImpl<T> implements Dao<T> {

	private SqlSessionTemplate sqlSession;

	@Autowired
	public void sqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
		this.sqlSession = sqlSessionTemplate;
	}

	@Override
	public List<T> selectList(String sqlId, HashMap<String, Object> map) throws Exception {
		return sqlSession.selectList(sqlId, map);
	}

	@Override
	public List<T> selectList(String sqlId, String username) throws Exception {
		return sqlSession.selectList(sqlId, username);
	}

	@Override
	public T selectOne(String sqlId, String username) throws Exception {
		return sqlSession.selectOne(sqlId, username);
	}

}

인증을 위해 사용자 정보를 가져올 수 있게 UserDetailService 인터페이스를 구현한다.

package com.dbility.spring.cloud.security.service;

import java.util.HashMap;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.dbility.spring.cloud.security.dao.Dao;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	private Dao<HashMap<String,Object>> dao;

	@Resource(name = "passwordEncoder")
	private PasswordEncoder passwordEncoder;


	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		log.debug("param ---------> {}", username);

		UserDetails details;
		try {
			HashMap<String,Object> user = dao.selectOne("member.selectMember", username);
			log.debug("user --------------> {}", user);

			if(user == null) {
				throw new UsernameNotFoundException("User Not Found");
			}

			List<HashMap<String,Object>> authorities = dao.selectList("role.selectListRole", username);
			log.debug("authorities --------> {}", authorities);

			if(authorities==null || authorities.size() == 0) {
				throw new UsernameNotFoundException("User Role Not Found");
			}

			String[] auths = authorities.toArray(new String[0]);

			details = User.builder()
			.username(user.get("USERNAME").toString())
			.password(user.get("PASSWORD").toString())
			.roles(auths)
			.build();

		} catch (Exception e) {
			e.printStackTrace();
			throw new UsernameNotFoundException(e.getMessage());
		}

		log.debug("details ----> {}", details);

		return details;
	}

}

Security 설정

package com.dbility.spring.cloud.security.config;

import javax.annotation.Resource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;

@Configuration
@EnableWebSecurity
public class ManuallySecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Resource(name = "userDetailsService")
	private UserDetailsService userDetailsService;

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http
		.authorizeRequests()
		.antMatchers("/nosecurity/datetime")
		.permitAll()
		.antMatchers("/h2-console/**").hasRole("ADMIN")
		.anyRequest()
		.authenticated()
		.and()
		.csrf().ignoringAntMatchers("/h2-console/**")
		.and()
		.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN))
		.frameOptions().disable()
		.and()
		.httpBasic()
		.and()
		.formLogin();
	}

	@Bean(name = "passwordEncoder")
	public PasswordEncoder passwordEncoder() {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
	}

}
반응형
Comments