스택큐힙리스트

자바 스프링 Spring Security 로그인·권한 관리 본문

개발

자바 스프링 Spring Security 로그인·권한 관리

스택큐힙리스트 2025. 7. 14. 22:44
반응형

1. 왜 Spring Security인가?

스프링 부트 프로젝트를 인터넷에 공개하는 순간, 누가 언제 어떤 요청을 보내는지 알 수 없습니다. 로그인으로 사용자를 식별하고, 권한(Role)으로 접근 범위를 구분해야 서비스와 데이터를 안전하게 지킬 수 있습니다. Spring Security는 필터 체인을 이용해 인증·인가 로직을 애플리케이션 앞단에서 처리해 주므로, 우리는 비즈니스 코드에만 집중할 수 있습니다.

2. 의존성 한 줄로 보안 프레임워크 탑재

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-security'

추가 후 애플리케이션을 재기동하면 기본 로그인 폼과 user-xxxx 형태의 임시 비밀번호가 콘솔에 출력됩니다. 이제 모든 요청이 인증을 요구하게 돼요.

3. SecurityConfig – Spring Boot 3 / Security 6 스타일

@Configuration
@EnableWebSecurity
@EnableMethodSecurity   // @PreAuthorize 등 활성화
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
          .csrf(csrf -> csrf.disable())
          .authorizeHttpRequests(auth -> auth
              .requestMatchers("/", "/login", "/css/**", "/js/**").permitAll()
              .requestMatchers("/admin/**").hasRole("ADMIN")
              .anyRequest().authenticated()
          )
          .formLogin(form -> form
              .loginPage("/login")          // 커스텀 로그인 페이지
              .defaultSuccessUrl("/")       // 로그인 성공 시 이동
              .permitAll()
          )
          .logout(logout -> logout
              .logoutSuccessUrl("/")
          );
        return http.build();
    }

    @Bean                 // 데모용 인메모리 계정
    UserDetailsService users() {
        return new InMemoryUserDetailsManager(
            User.withUsername("user")
                .password(passwordEncoder().encode("1234"))
                .roles("USER")
                .build(),
            User.withUsername("admin")
                .password(passwordEncoder().encode("1234"))
                .roles("ADMIN")
                .build()
        );
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  • SecurityFilterChain Bean 하나면 XML 없이도 보안 정책을 선언적(DSL)으로 설정 가능.
  • @EnableMethodSecurity를 켜 두면 서비스·컨트롤러 메서드에서 세밀한 권한 검사를 할 수 있습니다.

4. 커스텀 로그인 페이지

src/main/resources/templates/login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>로그인</title></head>
<body>
<h2>로그인</h2>
<form th:action="@{/login}" method="post">
  <input type="text" name="username" placeholder="아이디"><br>
  <input type="password" name="password" placeholder="비밀번호"><br>
  <button type="submit">로그인</button>
</form>
<a href="/">홈으로</a>
</body>
</html>
 

/login GET 요청을 허용하기 위해 컨트롤러에 다음 메서드를 추가합니다.

@GetMapping("/login")
public String login() { return "login"; }

5. Role 기반 권한 체크 – 메서드 수준

@Service
@RequiredArgsConstructor
public class PostService {
    private final PostRepository repo;

    @PreAuthorize("hasRole('ADMIN') or #post.writer == authentication.name")
    public Post edit(Post post) {
        return repo.save(post);
    }
}
  • ADMIN 계정이거나, 글 작성자와 로그인 사용자가 동일할 때만 수정 허용.
  • @PreAuthorize SpEL 식으로 복잡한 조건도 손쉽게 선언형으로 표현할 수 있습니다.

6. 비밀번호 암호화 필수!

프로덕션에서는 BCryptPasswordEncoder로 단방향 해시를 저장해야 합니다.
회원가입 시

user.setPassword(passwordEncoder.encode(rawPassword));

로그인 검증은 Spring Security가 자동으로 처리하므로 별도 로직이 필요 없습니다.

7. 핵심 정리

  • 의존성 1줄로 Spring Security 탑재 → 기본 로그인 폼 제공.
  • SecurityFilterChain Bean으로 URL 별 접근 제어를 선언.
  • PasswordEncoder로 비밀번호 안전하게 저장.
  • Role로 화면·API 권한을 분리하고, @PreAuthorize로 메서드 단위 제어.
  • 설정을 분리해 두면 OAuth2, JWT, 소셜 로그인도 쉽게 확장 가능!
반응형
Comments