기업회원 로그인 트러블슈팅

금은체리·2024년 6월 8일
0

프로젝트 진행 중 기업회원 로그인 기능을 추가하는 과정에서 다양한 이슈가 발생했습니다. 이 문서는 그 트러블슈팅 과정과 해결 방법을 상세히 기록한 것입니다. 이를 통해 발생할 수 있는 잠재적인 문제를 사전에 파악하고, 유사한 상황에서 효과적으로 대응할 수 있도록 돕기 위해 작성되었습니다.

문제 정의

기존 시스템에서는 일반 사용자 로그인 기능만을 제공하고 있었으며, 기업회원 로그인 기능이 추가됨에 따라 다음과 같은 문제들이 발생했습니다:
1. 기업회원과 일반 사용자의 구분 문제: 기업회원과 일반 사용자를 어떻게 구분하여 인증하고, 각 사용자 유형에 맞는 권한을 어떻게 부여할 것인가.
2. Security Configuration 문제: Spring Security 설정에서 기업회원과 일반 사용자의 접근 권한을 구분하여 설정하는 방법.
3. UserDetailsService 문제: 기업회원과 일반 사용자의 정보를 어떻게 로드할 것인가.

문제 해결 과정

1. 데이터베이스 스키마 수정

먼저, 기업회원과 일반 사용자를 구분할 수 있는 데이터베이스 스키마 수정이 필요했습니다. 이를 위해 User 테이블과 별도로 CompanyUser 테이블을 생성하고, 각각의 사용자 정보를 저장할 수 있도록 구성했습니다.

2. UserDetails 구현 수정

기존의 UserDetailsImpl 클래스는 일반 사용자만을 고려한 구조였습니다. 이를 수정하여 기업회원의 정보를 포함하도록 변경했습니다.

package team9502.sinchulgwinong.global.security;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

public class UserDetailsImpl implements UserDetails {

    private final String email;
    private final String password;
    private final Collection<? extends GrantedAuthority> authorities;
    private final String userType; // 추가된 필드

    public UserDetailsImpl(String email, String password, Collection<? extends GrantedAuthority> authorities, String userType) {
        this.email = email;
        this.password = password;
        this.authorities = authorities;
        this.userType = userType;
    }

    // 기존 메서드들...

    public String getUserType() {
        return userType;
    }
}
3. UserDetailsService 수정

UserDetailsServiceImpl 클래스를 수정하여 기업회원과 일반 사용자를 구분하여 로드할 수 있도록 했습니다.

package team9502.sinchulgwinong.global.security;

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.Service;
import team9502.sinchulgwinong.domain.user.entity.User;
import team9502.sinchulgwinong.domain.user.repository.UserRepository;
import team9502.sinchulgwinong.domain.companyuser.repository.CompanyUserRepository;

import java.util.Collections;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;
    private final CompanyUserRepository companyUserRepository;

    public UserDetailsServiceImpl(UserRepository userRepository, CompanyUserRepository companyUserRepository) {
        this.userRepository = userRepository;
        this.companyUserRepository = companyUserRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email).orElse(null);
        if (user != null) {
            return new UserDetailsImpl(user.getEmail(), user.getPassword(), Collections.emptyList(), "USER");
        }

        CompanyUser companyUser = companyUserRepository.findByEmail(email)
                .orElseThrow(() -> new UsernameNotFoundException(email + "으로 등록된 사용자를 찾을 수 없습니다."));
        return new UserDetailsImpl(companyUser.getEmail(), companyUser.getPassword(), Collections.emptyList(), "COMPANY_USER");
    }
}
4. Spring Security 설정 수정

Spring Security 설정을 통해 기업회원과 일반 사용자의 접근 권한을 구분했습니다.

package team9502.sinchulgwinong.global.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/", "/home", "/swagger-ui.html", "/v3/api-docs/**", "/swagger-ui/**").permitAll()
                        .requestMatchers("/auth/signup", "auth/login", "/auth/cp-signup", "/auth/cp-login").permitAll()
                        .requestMatchers("/business/status", "business/verify").permitAll()
                        .anyRequest().authenticated())
                .formLogin(AbstractAuthenticationFilterConfigurer::disable)
                .logout(LogoutConfigurer::permitAll);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }
}

최종 테스트 및 결과

위의 변경사항을 적용한 후, 기업회원과 일반 사용자가 각각 로그인을 시도했을 때 올바르게 인증 및 권한 부여가 이루어지는 것을 확인했습니다. 각 사용자 유형에 맞는 페이지 접근이 정상적으로 이루어졌으며, 이를 통해 보안성이 향상되었습니다.

profile
전 체리 알러지가 있어요!

0개의 댓글