본문 바로가기

스프링

스프링 시큐리티 UserDetailsService 설정

요약)

UserDetailsService 는 다중 구현체를 사용할 수 없으며 @Componenet 가 2개 이상 등록되면

AuthenticationManager.getObject() is null 에러가 뜹니다.

1개의 UserDetailsService 내에서 테이블 구분 메서드를 만들어서 해결하면 됩니다.


 

9월 18일 토이 프로젝트를 진행하던 중

Member , Market 테이블의 Mock 테스트를 완료한 후 

JWT 를 이용하여 로그인을 구현하려고하였다.

 

UserDetailsService 를 2중 구현하여 SecurityConfig에서 AuthenticationManagerBuilder 설정으로 관리할 수 있을 것으로 생각하여 UserDetailsService 구현체를 2개를 만든 후 SecurityConfig 를 2개를 만들어 

@Order , @Qualifier, @Primary 등 여러 설정을 반복하여 보며

스프링 시큐리티 구조를 계속 검색하여보았다. 독학이기에 구글링 , 스택오버플로우 , 오키 등 10일간 검색을 하였다.

 

websecurityconfigureradapter  인터페이스의 deprecated 해결 방법도 덕분에 알게되었다.

내린 결론은 UserDetailsService를 2개 이상 Componenet 등록하였을 시 마주한 Authentication.object is null 에러 또한

스프링이 UserDetailsService 의 구현체를 의존성 주입하지 못하기 때문에 일어난 일인 것을 깨닳았고

정말... 간단한 방법으로 10일간의 눈물흘리며 내 길이 아닌가까지 생각한 문제가 해결이 되었다.

 

이번 계기를 통해 느낀 점은 역시 안되는 것은 없다는 것이었다. 스트레스를 엄청 받았지만 해결하니 너무 뿌듯하였다.

 

아래는 코드입니다.

package hyeong.backend.domain.auth.details;

import hyeong.backend.domain.market.entity.persist.Market;
import hyeong.backend.domain.market.entity.vo.MarketEmail;
import hyeong.backend.domain.market.repository.MarketRepository;
import hyeong.backend.domain.member.Repository.MemberRepository;
import hyeong.backend.domain.member.entity.persist.Member;
import hyeong.backend.domain.member.entity.vo.MemberEmail;
import hyeong.backend.domain.member.exceptions.MemberNotFoundException;
import hyeong.backend.global.errors.exceptions.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Optional;

@Slf4j
@Component
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final MemberRepository memberRepository;
    private final MarketRepository marketRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

	// 삼항 연산자 사용
    // marketRepository (마켓 회원 값이 있을 경우) ?
    // market/Repository 에서 회원을 찾은 후 
    // map 을 이용 아래 구현한 메서드 실행 회원이 없으면 예외 발생 :
    // member Repository 에서 위와 동일하게 수행
 
        return !marketRepository.findByEmail(MarketEmail.from(email)).isEmpty() ? marketRepository.findByEmail(MarketEmail.from(email))
                .map(this::createdUserDetailsMarket)
                .orElseThrow(() -> new MarketNotFoundException((ErrorCode.MARKET_NOT_FOUND))) : memberRepository.findByEmail(MemberEmail.from(email))
                .map(this::createdUserDetailsMember)
                .orElseThrow(() -> new MemberNotFoundException((ErrorCode.MEMBER_NOT_FOUND)));
    }

    private UserDetails createdUserDetailsMember(Member member) {
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_" + member.getRoleType());

        return new User(member.getEmail().email(),
                member.getPassword().password(),
                Collections.singleton(grantedAuthority));
    }

    private UserDetails createdUserDetailsMarket(Market market) {
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_" + market.getRoleType());

        return new User(market.getEmail().email(),
                market.getPassword().password(),
                Collections.singleton(grantedAuthority));
    }
}

 

 

'스프링' 카테고리의 다른 글

[스프링부트] Junit5 설정 에러 모음  (0) 2022.10.26