스프링 기초_Security_6

bitna's study note·2022년 7월 24일

스프링

목록 보기
30/54

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타입의 객체로 변환해서 반환합니다.

profile
좋은개발자가 되기위한 삽질기록 노트

0개의 댓글