Engineering Note

[Spring] Spring Security 적용하고 테스트 하기 본문

Server

[Spring] Spring Security 적용하고 테스트 하기

Software Engineer Kim 2025. 12. 10. 18:00

Spring Boot 프로젝트를 만들고 Security를 적용하고 테스트 한 과정입니다.

 

1. gralde Security 의존성

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

 

 

2. Member Entity

package com.shop.rest.commerce.entity;

import com.shop.rest.commerce.constant.Role;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name="member")
@Getter @Setter
@ToString
public class Member extends BaseEntity {
    @Id
    @Column(name="member_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Column(unique = true)
    private String email;

    private String password;

    private String address;

    @Enumerated(EnumType.STRING)
    private Role role;

}

 

 

3. Member Repository

package com.shop.rest.commerce.repository;

import com.shop.rest.commerce.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {
    Member findByEmail(String email);
}

 

 

4. Security Config

package com.shop.rest.commerce.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())  // REST API는 CSRF 비활성화
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // JWT 사용 시 세션 사용 안함
                )
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/public/**", "/api/auth/**").permitAll()  // 인증 없이 접근 가능
                        .requestMatchers("/api/admin/**").hasRole("ADMIN")  // ADMIN만 접근 가능
                        .anyRequest().authenticated()  // 나머지는 인증 필요
                );

        return http.build();
    }

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

 

 

 

4. TestController

- Security 적용을 테스트하기 위한 테스트용 컨트롤러

 

package com.shop.rest.commerce.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/api")
public class TestController {

    // 인증 없이 접근 가능
    @GetMapping("/public/hello")
    public Map<String, String> publicHello() {
        return Map.of(
                "message", "Public API - 인증 없이 접근 가능",
                "status", "success"
        );
    }

    // 인증 필요
    @GetMapping("/user/hello")
    public Map<String, String> userHello() {
        return Map.of(
                "message", "User API - 인증 필요",
                "status", "success"
        );
    }

    // ADMIN 권한 필요
    @GetMapping("/admin/hello")
    public Map<String, String> adminHello() {
        return Map.of(
                "message", "Admin API - ADMIN 권한 필요",
                "status", "success"
        );
    }

    // 인증 필요 (모든 역할)
    @GetMapping("/protected/hello")
    public Map<String, String> protectedHello() {
        return Map.of(
                "message", "Protected API - 인증된 사용자만 접근 가능",
                "status", "success"
        );
    }
}

 

5. AuthContoller

- 회원가입용 컨트롤러

package com.shop.rest.commerce.controller;

import com.shop.rest.commerce.entity.Member;
import com.shop.rest.commerce.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

    private final MemberService memberService;
    private final PasswordEncoder passwordEncoder;

    @PostMapping("/register")
    public Map<String, String> register(@RequestBody Member member) {
        // 비밀번호 암호화
        member.setPassword(passwordEncoder.encode(member.getPassword()));

        Member savedMember = memberService.saveMember(member);

        return Map.of(
                "message", "회원가입 성공",
                "email", savedMember.getEmail()
        );
    }
}

 

6. Security 테스트

# 1. Public API (인증 없이 접근 가능) ✅
curl http://localhost:8080/api/public/hello

# 2. User API (인증 필요) ❌ 401 Unauthorized
curl http://localhost:8080/api/user/hello

# 3. Admin API (ADMIN 권한 필요) ❌ 401 Unauthorized
curl http://localhost:8080/api/admin/hello

# 4. Protected API (인증 필요) ❌ 401 Unauthorized
curl http://localhost:8080/api/protected/hello

# 5. 회원가입 (인증 없이 가능) ✅
curl -X POST http://localhost:8080/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@test.com",
    "password": "1234",
    "name": "테스트",
    "role": "USER"
  }'

 

 

예상 결과:

엔드포인트 인증 예상 결과
/api/public/hello 200 OK + JSON
/api/user/hello 401 Unauthorized
/api/admin/hello 401 Unauthorized
/api/protected/hello 401 Unauthorized
/api/auth/register 200 OK + 회원가입 성공
Comments