스프링시큐리티 두개의 엔티티로 로그인

이건구·2023년 12월 15일
0

스프링시큐리티를 통한 폼로그인

여러개의 엔티티(데이터)로 로그인하는 방법

스프링 시큐리티를 통한 폼로그인

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                .requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
            .formLogin((formLogin) -> formLogin
                .loginPage("/user/login")
                .defaultSuccessUrl("/"))
        ;
        return http.build();
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
@RequiredArgsConstructor
@Service
public class UserSecurityService implements UserDetailsService {
    private final UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<SiteUser> _siteUser = this.userRepository.findByusername(username);
        if (_siteUser.isEmpty()) {
            throw new UsernameNotFoundException("사용자를 찾을수 없습니다.");
        }
        SiteUser siteUser = _siteUser.get();
        List<GrantedAuthority> authorities = new ArrayList<>();
        if ("admin".equals(username)) {
            authorities.add(new SimpleGrantedAuthority(UserRole.ADMIN.getValue()));
        } else {
            authorities.add(new SimpleGrantedAuthority(UserRole.USER.getValue()));
        }
        return new User(siteUser.getUsername(), siteUser.getPassword(), authorities);
    }
}

스프링시큐리티의 설정 클래스인 SecurityConfig 클래스를 위처럼 설정해두면 html에서 Post방식으로 /user/login에 보낸 정보를 Controller에서 PostMapping을 안해줘도 스프링에서 UserDetailsService에서 리턴해주는 User를 찾아서 로그인을 수행해준다.

여러개의 엔티티로 폼로그인하는 방법

위에서 사용한 폼로그인은 UserDetailsService에서 지정해준 유저 정보를 기반으로 로그인 진행해준다.

이때 만약 유저정보를 두개의 엔티티로(다른 테이블)에 저장하게된다면 각자의 테이블에는 중복되는 정보가 저장될 수 있어서 loadUserByUsername메서드로 찾고자하는 유저를 찾기가 어려워진다.

그렇기 때문에 자동으로 스프링에서 로그인하려는 유저가 누구인지 데이터베이스에서 매칭해주지 못하기때문에 수동으로 제공해줘야한다.

	@Bean
    DaoAuthenticationProvider ownerDaoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(new OwnerDetailsService(ownerRepository));
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return daoAuthenticationProvider;
    }
    @Bean
    DaoAuthenticationProvider customerDaoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(new CustomerDetailsService(customerRepository));
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return daoAuthenticationProvider;
    }

임의로 두개의 유저 엔티티를 owner와 customer로 설정했고 로그인할때 사용하기 위해서 SecurityConfig 클래스에 구현해주었다.

그리고 filterChain 메서드를 두개로 구현해주고

.authenticationProvider(ownerDaoAuthenticationProvider())

이걸추가해준다. 완성된 SecurityConfig의 모습은 이렇다.

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    private final CustomerRepository customerRepository;
    private final OwnerRepository ownerRepository;
    private final Oauth2UserService oauth2UserService;
    @Bean
    @Order(1)
    public SecurityFilterChain ownerFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher(new AntPathRequestMatcher("/owner/**"))
                .authenticationProvider(ownerDaoAuthenticationProvider())
                .authorizeHttpRequests(authorizeHttpRequests ->
                        authorizeHttpRequests
                                .requestMatchers(new AntPathRequestMatcher("/**"))
                                .permitAll())
                .formLogin(formLogin -> formLogin
                        .loginPage("/owner/login")
                        .defaultSuccessUrl("/")
                        .permitAll()
                        .failureHandler(new OwnerFailureHandler()))
                .logout((logout) -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
                        .logoutSuccessUrl("/")
                        .invalidateHttpSession(true));
        return http.build();
    }
    @Bean
    @Order(2)
    public SecurityFilterChain customerFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/owner/**")))
                .authenticationProvider(customerDaoAuthenticationProvider())
                .authorizeHttpRequests(authorizeHttpRequests ->
                        authorizeHttpRequests
                                .requestMatchers(new AntPathRequestMatcher("/**"))
                                .permitAll())
                .formLogin(formLogin -> formLogin
                        .loginPage("/customer/login")
                        .defaultSuccessUrl("/")
                        .permitAll()
                        .failureHandler(new CustomerFailureHandler()))
                .logout((logout) -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
                        .logoutSuccessUrl("/")
                        .invalidateHttpSession(true));
        return http.build();
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    DaoAuthenticationProvider ownerDaoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(new OwnerDetailsService(ownerRepository));
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return daoAuthenticationProvider;
    }
    @Bean
    DaoAuthenticationProvider customerDaoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(new CustomerDetailsService(customerRepository));
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return daoAuthenticationProvider;
    }
}

2개의 댓글

comment-user-thumbnail
2024년 5월 7일

지렸습니다 이글을 애타게 찾고있었습니다

답글 달기
comment-user-thumbnail
2024년 11월 28일

헉 감사합니다.... 혼자 작업중 회원 정보들이 너무 달라서 테이블을 만들어버려서 어찌해야하나 했는데... 큰 도움이 되었습니다 ㅜㅜ 감사합니다

답글 달기