부트모아

[V1] 사용자 인증 구현

승무_ 2024. 9. 28. 14:40

Spring Security 공식 문서 Spring Security without the WebSecurityConfigurerAdapter를 참고하여 인증 구현을 진행하였습니다.

 

UserDetails
spring security에서 사용자의 정보를 담는 인터페이스
CustomUserDetails(Principal)
대부분의 경우 spring security의 기본 UserDetails로는 실무에서 필요한 정보를 모두 담을 수 없기에
Principal을 구현하여 사용한다.
@Setter
@Getter
public class BootPrincipal implements UserDetails {
    private String username;
    private String password;
    Collection<? extends GrantedAuthority> authorities;

    public BootPrincipal(String username, String password) {
        Set<RoleType> roleTypes = Set.of(RoleType.USER);
        this.username = username;
        this.password = password;
        this.authorities = roleTypes.stream()
                .map(RoleType::getName)
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toUnmodifiableSet());
    }

    public static BootPrincipal from(UserAccountDto userAccountDto){
        return new BootPrincipal(
                userAccountDto.getUserId(),
                userAccountDto.getUserPassword()
        );
    }

    public UserAccountDto toDto(){
        return new UserAccountDto(
                username,
                password
        );
    }


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }


    public enum RoleType{
        USER("ROLE_USER");

        @Getter
        private final String name;

        RoleType(String name) {
            this.name = name;
        }
    }
}
UserDetailsService
spring security에서 유저의 정보를 가져오는 인터페이스
@Bean
public UserDetailsService userDetailsService(UserAccountRepository userAccountRepository){
    return username -> userAccountRepository
            .findById(username)
            .map(UserAccountDto::from)
            .map(BootPrincipal::from)
            .orElseThrow(() -> new UsernameNotFoundException("유저를 찾을 수 없습니다."));
}

 

인증 기능이 구현되었기 때문에 인증된 사용자로부터 사용자 정보를 받을 수 있게 되었다.

@EnableJpaAuditing
@Configuration
public class JpaConfig {
	
    @Bean
    public AuditorAware<String> auditorAware() {
        return () -> Optional.of("swkang");
    }
}

이전에 사용자 인증을 구현하지 않아 임시 데이터를 넣어주었던 부분을 이제

@Bean
public AuditorAware<String> auditorAware() {
    return () -> Optional.ofNullable(SecurityContextHolder.getContext())
            .map(SecurityContext::getAuthentication)
            .filter(Authentication::isAuthenticated)
            .map(Authentication::getPrincipal)
            .map(x -> (BootPrincipal) x)
            .map(BootPrincipal::getUsername);
}

다음과 같이 Spring Security를 사용해 가져올 수 있다.

1. SecurityContextHolder로부터 SecurityContext를 불러온다.
2. SecurityContext에는 Authentication 정보가 있는데, 인증된 정보인지 확인하여 필터링한다.
3. Authentication에서 Principal 정보를 가져온다.
4. Principal 정보는 Object로 넘어오게 되는데 이를 구현한 BoardPrincipal 형태로 타입 캐스팅한다.
5. BoardPrincipal 에서 Username정보를 불러온다.