인증 및 권한 DB 연동

UserDetailsService

Spring Security에서는 username의 사용자정보만 사용하기 때문에 다양한 활용에 비효율적인 단점이 있습니다.

이를 해결하기 위해 원하는 객체(사용자 VO)의 권한과 인증을 확인할 수 있는 CustomUserDetailsService 를 사용합니다.

사용할 CustomUserDetailsService 클래스를 생성합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Log4j
public class CustomUserDetailsService implements UserDetailsService{
	
  @Autowired
	@Setter
	private MemberMapper mapper;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		
		log.warn("Load UserName : " + username);
		
		return null;
	}
	
}

작동하는지 확인하기 위해 log만 남기고 security-context.xml에 bean을 등록합니다.

1
2
3
<bean id="CustomUserDetailsService" class="org.zerock.security.CustomUserDetailsService"></bean>

<security:authentication-provider user-service-ref="CustomUserDetailsService">

authentication-provider 태그 user-service-ref속성에 등록한 bean의 ID값을 지정해줍니다.

서버를 켜서 로그인을 해보면 log에 warn : org.zerock.security.CustomUserDetailsService - Load UserName : admin90 이 찍히는것을 확인할 수 있습니다.


UserDetails 리턴타입

CustomUserDetailsService 클래스는 UserDetailsService 인터페이스를 상속받아 DB에서 사용자의 정보를 불러오는 메소드인 loadUserByUsername() 를 오버라이딩합니다. 이 메소드의 리턴 타입은 UserDetails 를 사용합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  @Autowired
	@Setter
	private MemberMapper mapper;

	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		
		log.warn("Load UserName : " + username);
		
		MemberVO vo = mapper.read(username);
		
		log.warn("member mapper : " + vo);
		
		
		if(vo == null) {
			throw new UsernameNotFoundException(username);
		} else {
			return new CustomUser(vo);
		}
	}
	

이후 기존의 클래스를 건드리지 않기 위해 User 클래스를 상속한 CustomUser 객체를 만들어 생성자를 통해 변환합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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()));
		
	//변환한 객체를 member필드에 넣어줍니다.
		this.member = vo;
	}
	

}

이후 서버를 켜고 브라우저에서 로그인을 하면 콘솔창에서 다음과 같이 로그인한 유저를 확인할 수 있습니다.

1
2
WARN : org.zerock.security.CustomUserDetailsService - Load UserName : admin95
WARN : org.zerock.security.CustomUserDetailsService - member mapper : MemberVO(userId=admin95, userPw=$2a$10$cbRdSFvVP/RZvDSzu0x0Je5nJfA6tBBL3X3LG2ue5F8wjWWA/EDge, userName=관리자95, enabled=false, regDate=Wed May 22 15:43:09 KST 2019, updateDate=Wed May 22 15:43:09 KST 2019, authList=[AuthVO(userId=admin95, auth=ROLE_ADMIN)])

Reference