7월 25일
MyBatis를 이용해서 MemberVO와 같이 회원을 처리하는 부분이 구성되었다면 이를 이용해서 스프링 시큐리티의 UserDetailsService 를 구현하는 클래스를 직접 작성해야함.
작성하려는 CustomUserDetailsService는 스프링 시큐리티의 UserDetailsService를 구현하고,MemberMapper타입의 인스턴스를 주입받아서 실제기능을 구현합니다.
(1)CustomUserDetailsService 작성하기
package com.keduit.security;
@Log4j
public class CustomUserDetailsService implements UserDetailsService{
@Setter(onMethod_ = @Autowired)
private MemberMapper memberMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.warn("유져네임 뭐임?? "+username);
return null;
}
}
(2)security-context.xml 수정
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
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">
<bean id="customAccessDenied" class="com.keduit.security.CustomAccessDeniedHandler"></bean>
<bean id="customLoginSuccess" class="com.keduit.security.CustomLoginSuccessHandler"></bean>
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
<bean id="customUserDetailsService" class="com.keduit.security.CustomUserDetailsService"></bean>
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll"/>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')"/>
<!--/accessError 라는 uri로 접근제한 시 보이는 화면을 처리합니다-->
<security:access-denied-handler error-page="/customAccessDenied"/>
<!-- 로그인페이지 따로 URI 설정하기 -->
<security:form-login login-page="/customLogin"/>
<!-- 로그아웃 페이지 URI 설정하기 -->
<security:logout logout-url="/customLogout" invalidate-session="true"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="bcryptPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
</beans>
(3)MemberVO를 UserDetails타입으로 변환하기
스프링 시큐리티에서는 UserDetailsService에서 loadUserByUsername()라는 하나의 추상메서드를 가지고 있으며, 그 추상메서드의 리턴 타입은 UserDetails 다.
MemberVO의 인스턴스를 스프링 시큐리티의 UserDetails 리턴타입으로 변환하는 작업이 필요하다.
package com.keduit.domain;
@Getter
public class CustomUser extends User{
private static final long serialVersionUID=1L;
private MemberVO member;
public CustomUser(String username, String password,Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
public CustomUser(MemberVO vo) {
super(vo.getUserid(),vo.getUserpw(), vo.getAuthList().stream().map
(auth -> new SimpleGrantedAuthority(auth.getAuth())).collect(Collectors.toList()));
this.member=vo;
}
}

CustomUser는 User클래스를 상속 받았기 때문에 부모 클래스의 생성자를 호출해야만 정상적인 객체를 생성할 수 있음.
MemberVO를 파라미터로 전달헤서 User클래스에 맞게 생성자를 호출하고,
그 과정에서 AuthVO 인스턴스는 GrantedAuthority 객체로 변환해야 하므로 stream().map() 을 이용하여 처리함.
(4)CustomUserDetailsService
package com.keduit.security;
@Log4j
public class CustomUserDetailsService implements UserDetailsService{
@Setter(onMethod_ = @Autowired)
private MemberMapper memberMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.warn("유져네임 뭐임?? "+username);
MemberVO vo= memberMapper.read(username);
log.warn("지금 맞는 맴버mapper 뭐임??"+vo);
return vo==null? null:new CustomUser(vo);
}
}
loadUserByUsername()메서드의 내부적으로 MemberMapper를 이용해서 MemberVO를 조회하고,만일 MemberVO의 인스턴스를 얻을수 있다면 매개변수로 적용하여 CustomUser타입의 객체로 변환해서 반환합니다.