1. emp 테이블을 스프링 시큐리티에서 커스텀마이징 하시오.

1-1. 소스코드 (VO 객체)

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@ToString
public class EmpVO {
	/* private int empno; */
	private String empno; // NOT NULL NUMBER(4)
	private String ename; // VARCHAR2(10)
	private String job; // VARCHAR2(9)
	private int mgr; // NUMBER(4)
	private Timestamp hiredate; // DATE
	private int sal; // NUMBER(7,2)
	private int comm; // NUMBER(7,2)
	private int deptno; // NUMBER(2)

	private String authority;
	private List<AuthVO> authList;
}

 

1-2. 소스코드 (User 객체)

@Setter
@Getter
@ToString
// 스프링 시큐리티의 User 객체 상속
public class EmpUser extends User {
	private EmpVO emp;

	public EmpUser(String ename, String empno, Collection<? extends GrantedAuthority> authorities) {
		super(ename, empno, authorities);
	}

	public EmpUser(EmpVO empVO) {
		super(empVO.getEname(), empVO.getEmpno(), getAuth(empVO));
		this.emp = empVO;
	}

	// 유저가 갖고 있는 권한 목록
	public static Collection<? extends GrantedAuthority> getAuth(EmpVO empVO) {
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

		for (AuthVO auth : empVO.getAuthList()) {
			authorities.add(new SimpleGrantedAuthority(auth.getAuthority()));
		}
		return authorities;
	}
}

 

1-3. 소스코드 ( DetailsService 객체)

@Log4j
@Service

// 스프링 시큐리티의 UserDetailsService의 인터페이스 구현
public class EmpDetailsService implements UserDetailsService {
	@Setter(onMethod_ = @Autowired)
	private EmpMapper empMapper;

	@Override
	public UserDetails loadUserByUsername(String ename) throws UsernameNotFoundException {
		log.warn("Load User By EmpVO number: " + ename);
		EmpVO vo = empMapper.getEmp(ename);

		log.warn("Query by EmpVO mapper: " + vo);
		return vo == null ? null : new EmpUser(vo);
	}
}

 

1-4. 소스코드 ( Mapper 객체)

@Mapper
public interface EmpMapper {
	EmpVO getEmp(String ename);
}

 

1-5. 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="edu.bit.ex.mapper.EmpMapper">
	<resultMap id="empMap" type="edu.bit.ex.vo.EmpVO">
	    <result property="ename" column="ename"/>
	    <result property="empno" column="empno"/>
	    <result property="hiredate" column="hiredate"/> 
	    <result property="mgr" column="mgr"/> 
	    <result property="sal" column="sal"/>
	    <result property="comm" column="comm"/>   
	    <result property="deptno" column="deptno"/> 
	    <result property="authority" column="authority"/>
	    <collection property="authList" resultMap="authMap"></collection>
	</resultMap>
	
	<resultMap id="authMap" type="edu.bit.ex.vo.AuthVO">
		<result property="username" column="ename"/>
		<result property="authority" column="authority"/>
	</resultMap>
	
	<select id="getEmp" resultMap="empMap">
		SELECT empno, ename, mgr, hiredate, sal, comm, deptno, 
			CASE WHEN job = 'MANAGER' 
			THEN 'ROLE_ADMIN' 
			ELSE 'ROLE_USER' 
			END authority 
		FROM emp01 
		WHERE ename = #{ename}
	</select>
</mapper>

 

1-6. Context XML 파일

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
   xmlns:beans="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/security 
      http://www.springframework.org/schema/security/spring-security.xsd 
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd">
   
   <!-- 해당 프로토콜의 로그인 감지 -->
   <http auto-config="true" use-expressions="true">
      <!-- 권한을 부여하여 해당 조건을 만족하지 않을때 로그인 페이지로 인터셉트한다 -->
      <intercept-url pattern="/login/loginForm" access="permitAll" />
	  <intercept-url pattern="/" access="permitAll" />
	  <intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
      <intercept-url pattern="/user/**" access="permitAll" />
	  <intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')" />
      
      <!-- 로그인 폼 구현 -->
      <!-- form-login 태그로 기초적인 형태가 구축되고 속성값에 의해 커스터마이징 할 수 있다 -->
      <form-login login-page="/login/loginForm"
                    default-target-url="/"
                    authentication-failure-url="/login/loginForm?error"
                    username-parameter="id" 
                    password-parameter="password" />
      <!-- 로그아웃 폼 구현 -->
      <logout logout-url="/logout" logout-success-url="/" /> 
     
      <!-- 403(접근 거부) 에러 처리 -->
      <!-- 인증값과 권한값이 매칭이 안될경우 발생시킨다 -->
      <access-denied-handler error-page="/login/accessDenied"/>
   </http>
   
   <!-- 암호화 인코딩 객체 설정 -->
   <beans:bean id="customNoOpPasswordEncoder" class="edu.bit.ex.security.CustomNoOpPasswordEncoder"/>/>
   
   <!-- DetailsService 설정  -->
   <beans:bean id="empDetailsService" class="edu.bit.ex.security.EmpDetailsService" />
   
   <!-- provider -->
   <!-- DB에서 설정한 쿼리문으로 필요한 데이터들을 불러온다 --> 
   <authentication-manager>
      <authentication-provider user-service-ref="empDetailsService">
      	 <!-- 패스워드 인코딩을 설정한다 -->
      	 <password-encoder ref="customNoOpPasswordEncoder"/>  
      </authentication-provider>
   </authentication-manager>
</beans:beans>

 

1-7. 소스코드 (UserService 객체)

@Log4j
@NoArgsConstructor
@Service
public class UserService {
	@Inject
	private CustomNoOpPasswordEncoder passEncoder;
	@Inject
	private UserMapper userMapper;

	@Transactional(rollbackFor = Exception.class)
	public void addUser(UserVO userVO) {
		String password = userVO.getPassword();
		String encode = passEncoder.encode(password);

		userVO.setPassword(encode);

		userMapper.insertUser(userVO);
		userMapper.insertAuthorities(userVO);
	}
}

'WebDev > 본과정' 카테고리의 다른 글

Log4j와 스프링 부트 기초  (0) 2021.05.17
스프링 시큐리티의 세션, 공격기법 대처 및 소셜 로그인  (0) 2021.05.17
카카오톡 소셜로그인  (0) 2021.05.17
Spring Security  (0) 2021.05.17
목표 지향 프로그래밍  (0) 2021.05.17