[Spring Security] 스프링 시큐리티로 로그인 기능 구현하기

jihun Choi·2023년 10월 8일
4

안녕하세요 오늘은 스프링 시큐리티를 사용하여 로그인 기능을 구현해 보도록 하겠습니다

😎 Spring Security란?

Spring Security는 Spring Boot의 하위 프레임 워크이며 Java 어플리케이션에 인증과 권한 부여를 제공하는데 중점을 둔 프레임워크입니다. Spring에서는 사실상 Spring Security를 표준으로 하여 보안기능을 제공하며 필터기반으로 처리합니다. 사용자의 ID와 PASSWORD를 입력받아 인증을 하고 역할 및 권한을 부여할 수 있으며 CSRF(Cross Stie Script Forgery) 같은 취약점에도 대응이 가능합니다.


지금부터 spring security를 사용해 로그인 기능을 구현해 보도록 하겠습니다

😎 spring security 의존성 추가

spring security를 사용하기 위해서는 하단 코드를 build.gradle에 넣어줘야 합니다

	implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
	implementation 'org.springframework.boot:spring-boot-starter-security'

스프링 시큐리티를 사용하기 위해 스프링 시큐리티에 필요한bean을 추가해주는 config 클래스 파일을 추가해 줘야 합니다

@EnableWebSecurity
@EnableMethodSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {

    @Bean
    public static BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations());
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(requests -> requests
                        .requestMatchers("/", "/login", "/join").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .defaultSuccessUrl("/", true)
                        .permitAll()
                )
                .logout(logout -> logout
                        .permitAll());

        return http.build();
    }

}
  • BCryptPasswordEncoder : password 암호화를 위해 BCryptPasswordEncoder클래스를 생성하여 빈에 등록해주었습니다.
  • WebSecurityCustomizer : resouces를 접근할수 있도록 빈을 추가해주었습니다
  • securityFilterChain
    • csrf : 로컬에서 확인을 위해 csrf를 비활성화 시켜주었습니다
    • authorizeHttpRequests : /(홈), /login(로그인 페이지), /join(회원가입 페이지)는 로그인 없이 접근하도록 셋팅하였습니다
    • formLogin : /login 페이지를 커스터마이징 하여 로그인 체크를 할때 해당 url을 타도록 셋팅하고 로그인 성공시 /로 페이지 이동하도록 하였습니다

로그인 페이지에서 로그인을 할때 url호출없이 service를 이용할수 있는 로직을 spring security에서 제공해줍니다

@Service
@RequiredArgsConstructor
public class AccountService implements UserDetailsService{

    private final UserMapper userMapper;
    private final BCryptPasswordEncoder encoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = new Account();
        account.setId(username);
        account = userMapper.findUser(account);
        if(account != null){
            List<GrantedAuthority> authorities = new ArrayList();
            return new User(account.getId(), account.getPasswd(), authorities);
        }
        return null;
    }

    @Transactional
    public boolean join(String userId, String userPwd) {
        Account checkUser = new Account();
        checkUser.setId(userId);

        if (userMapper.findUser(checkUser) != null){
            return false;
        }
        Account newUser = new Account();
        newUser.setId(userId);
        newUser.setPasswd(encoder.encode(userPwd));
        userMapper.save(newUser);
        return true;
    }

}

UserDetailsService 인터페이스를 상속받아 loadUserByUsername 메서드를 오버라이딩 하여 로그인시 로그인 체크를 할수 있도록 로직을 구현하였습니다


@Getter
@Setter
public class Account implements UserDetails {
    private String id;
    private String passwd;
    private String authority;

    @Override
    public String getUsername() {
        return this.id;
    }
    ...

사용자 VO에 UserDetails 인터페이스를 상속받으면 html에서 뿐아니라 백앤드단에서도 로그인되어있을때 자유롭게 로그인 체크나 로그인 데이터를 가져와서 체크를 할수 있습니다


로그인 여부를 확인하기 위해 util파일을 만들어 주었습니다

public class LoginUtil {

    public static boolean isLogin(){
        boolean result = true;

        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(principal instanceof String){
            result = false;
        }

        return result;
    }
}

SecurityContextHolder.getContext().getAuthentication().getPrincipal() 을 사용해 로그인 정보를 가져올수 있습니다


😎 실행결과



실행 결과 정상적으로 로그인, 회원가입기능이 구현되는것을 확인할수 있었습니다 다음번엔 더 재미있는 소재로 찾아뵙겠습니다 감사합니다.

profile
성장을 위해 열심히 노력하는 개발자 입니다

1개의 댓글

comment-user-thumbnail
2024년 1월 26일

안녕하세요! 제가 지금 스프링부트 3.1.7, 스프링시큐리티6을 사용중인데 BCryptPasswordEncoder클래스를 생성하는 코드에서 @Bean어노테이션을 다니 어노테이션은 이곳에 허용되지 않는다라고 하네요 버전이 달라서 그런거겠죠?

답글 달기