[RestAPI] REST API 구현을 위한 HATEOAS 적용

wony·2024년 5월 29일

Spring

목록 보기
28/33

섹션 4. Spring Boot API 사용

Level3 단계의 REST API 구현을 위한 HATEOAS 적용

  • HATEOAS(Hypermedia As The Engine Of Application State)REST API 디자인 패턴 중 하나로, 클라이언트가 애플리케이션의 다른 부분과 상호작용할 수 있는 방법을 포함하도록 리소스를 설계하는 방법입니다.
  • HATEOAS 의 주요 목표는 클라이언트가 서버의 응답을 통해 애플리케이션의 가능한 상태 전환을 발견할 수 있도록 하는 것입니다.
  • HATEOAS 를 구현하면 클라이언트는 API 의 구조를 미리 알 필요 없이, 서버가 제공하는 링크를 따라 애플리케이션을 탐색하고 상호작용할 수 있습니다.
  • 이를 통해 클라이언트는 동적으로 서버의 상태 전환을 이해하고, 애플리케이션의 다른 리소스에 접근할 수 있습니다.

1. Swagger Documentation 구현 - Spring Boot 2.7 사용 ①

  • 우리가 사용한 사용자 관리 RESTful API 의 개발자 도움말 페이지를 생성해보자.
  • 이러한 작업을 하기 위해서는 Swagger 라는 오픈소스 프레임워크를 사용해서 이러한 개발자 도움말 페이지를 생성해봅니다.
  • Swaager 프로젝트는 API의 단순한 JSON 표현을 목적으로 만들어졌습니다.
  • SpringBoot 에서는 Swagger 를 사용하기 위해 두 가지 방법이 제공됩니다.
    • Springfox
    • Springdoc OpenAPI

1) Springfox를 사용한 방법

  • Springfox 는 오래된 라이브러리로, Spring Boot 애플리케이션에서 Swagger 를 통합하는 데 널리 사용되었습니다. 그러나 Springfox 는 현재 활발히 유지보수되고 있지 않으며, 최신 Spring Boot 버전과의 호환성 문제가 있을 수 있습니다.

2) Springfox 설치 및 설정

  1. 의존성 추가:
    <!-- pom.xml -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>


2. Swagger Configuration 클래스 생성:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
.apis(RequestHandlerSelectors.basePackage("com.example.yourpackage"))
                .paths(PathSelectors.any())
                .build();
    }
}
  1. Swagger UI 접근:
    Spring Boot 애플리케이션을 실행한 후 브라우저에서 http://localhost:8080/swagger-ui.html에 접근하면 Swagger UI를 통해 API 문서를 확인할 수 있습니다.

3) Springdoc OpenAPI를 사용한 방법

  • Springdoc OpenAPISpringfox의 대안으로, OpenAPI 3.0 표준을 지원하며 Spring Boot 와의 호환성이 좋습니다. Springdoc OpenAPI 는 현재 가장 권장되는 방법입니다.

4) Springdoc OpenAPI 설치 및 설정

  1. 의존성 추가:
    <!-- pom.xml -->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-ui</artifactId>
        <version>1.6.7</version>
    </dependency>
  1. 기본 설정:
  • 특별한 설정이 필요하지 않으며, Spring Boot 애플리케이션에 의존성만 추가하면 됩니다.
  1. Swagger UI 접근:
  • Spring Boot 애플리케이션을 실행한 후 브라우저에서 http://localhost:8080/swagger-ui.html 또는 http://localhost:8080/swagger-ui/index.html에 접근하면 Swagger UI 를 통해 API 문서를 확인할 수 있습니다.

비교

  • SpringfoxSwagger 2.0 을 사용하며, 현재 유지보수 상태가 좋지 않아 최신 프로젝트에서는 사용을 지양하는 것이 좋습니다.
  • Springdoc OpenAPIOpenAPI 3.0 을 사용하며, 최신 표준을 지원하고 Spring Boot와의 호환성이 좋아 권장됩니다.

이 두 가지 방법 중에서 최신 표준을 지원하고 더 나은 유지보수를 제공하는 Springdoc OpenAPI를 사용하는 것이 좋습니다.

2. Swagger Documentation 구현 - Spring Boot 2.7 사용 ②

  • Spring Boot 2.7에서 Swagger 문서를 구현하기 위해 Springdoc OpenAPI를 사용하는 방법.
  • Springdoc OpenAPISpring BootOpenAPI 3.0 표준을 쉽게 통합할 수 있도록 도와줍니다.

1) Springdoc OpenAPI 설정 및 사용 방법

  1. 의존성 추가:
    먼저 pom.xml 파일에 Springdoc OpenAPI 관련 의존성을 추가합니다.
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-ui</artifactId>
        <version>1.6.7</version>
    </dependency>
  1. Spring Boot 애플리케이션 실행:
    • Springdoc OpenAPI는 특별한 설정 없이 기본적으로 작동합니다.
    • 애플리케이션을 실행하면 자동으로 API 문서를 생성합니다.
  1. Swagger UI 접근:
    • 애플리케이션을 실행한 후 브라우저에서 Swagger UI를 통해 API 문서를 확인할 수 있습니다.
    • 기본 URL : http://localhost:8080/swagger-ui/index.html

2) 예제 프로젝트 설정

  1. 의존성 추가:
    <!-- pom.xml -->
    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Springdoc OpenAPI UI -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.7</version>
        </dependency>
    </dependencies>
  1. 컨트롤러 작성:
  • 간단한 REST API 컨트롤러를 작성합니다.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}
  1. Spring Boot 애플리케이션 클래스:
    Spring Boot 애플리케이션을 실행하는 기본 클래스를 작성합니다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SwaggerDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SwaggerDemoApplication.class, args);
    }
}
  1. Swagger UI 접근:
    애플리케이션을 실행한 후 브라우저에서 http://localhost:8080/swagger-ui/index.html에 접근하여 Swagger UI를 통해 API 문서를 확인합니다.

3) 추가 설정 (선택 사항)

  • Springdoc OpenAPI 는 다양한 커스터마이징 옵션을 제공합니다.
  • API 문서의 기본 정보를 설정하고 싶다면 application.properties 파일에 다음과 같은 설정을 추가하는 방법과 자바 코드 로 추가하는 방법 존재합니다.
// 1. application.properties
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
// 2. 자바 코드
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.OpenAPI;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                .title("Spring Boot REST API Documentation")
                .version("1.0")
                .description("This is a sample Spring Boot RESTful service using springdoc-openapi and OpenAPI 3."));
    }

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("public")
                .pathsToMatch("/api/**")
                .build();
    }
}
  • 이렇게 하면 Swagger UI에서 보다 자세한 API 문서를 확인할 수 있습니다.

3. Swagger Documentation 구현 - Spring Boot 3.1 사용 ①

4. Swagger Documentation 구현 - Spring Boot 3.1 사용 ②

  • Swagger 를 사용하여 Spring Boot 애플리케이션의 API 문서를 자동으로 생성할 수 있습니다.
  • Swagger는 OpenAPI 사양을 사용하여 RESTful API의 정의를 작성하고, 이를 통해 API를 탐색하고 테스트할 수 있는 웹 인터페이스를 제공합니다.
  • 아래의 예시 코드는 Spring Boot 3.1에서 Swagger 문서를 설정하고 사용하기 위한 방법을 설명합니다.

1) OpenAPI 정의 정보 추가

OpenAPI 정의를 작성하려면 @OpenAPIDefinition 어노테이션을 사용합니다. 이 어노테이션은 API의 전반적인 정보를 제공하는 info 객체를 포함합니다.

@OpenAPIDefinition(
    info = @Info(
        title = "My Restful Service API 명세서",
        description = "Spring Boot로 개발하는 RESTful API 명세서입니다.",
        version = "v1.0.0"
    )
)
  • 이 코드는 API 문서의 제목, 설명 및 버전 정보를 정의합니다.

2) Swagger Config 클래스 작성

  • Swagger 설정을 위한 Configuration 클래스를 작성합니다.
  • 여기서 @Configuration@Bean 어노테이션을 사용하여 Swagger 설정을 초기화합니다.
@Configuration
@RequiredArgsConstructor
public class NewSwaggerConfig {

    @Bean
    public GroupedOpenApi customTestOpenAPI() {
        String[] paths = {"/user/**", "/admin/**"};

        return GroupedOpenApi.builder()
            .group("일반 사용자와 관리자를 위한 User 도메인에 대한 API")
            .pathsToExclude(paths)
            .build();
    }
}
  • 위 코드에서는 /user/**/admin/** 경로를 제외하고 나머지 경로에 대한 API 문서를 생성하도록 설정합니다.

3) User 도메인 객체에 Schema 어노테이션 추가

Swagger 문서에 포함될 도메인 객체에 @Schema 어노테이션을 추가하여 필드 설명을 작성합니다.

@Schema(description = "사용자 상세 정보를 위한 도메인 객체")
@Entity
@Table(name = "users")
public class User {

    @Schema(title = "사용자 ID", description = "사용자 ID는 자동 생성됩니다.")
    @Id
    @GeneratedValue
    private Integer id;

    @Schema(title = "사용자 이름", description = "사용자 이름을 입력합니다.")
    @Size(min = 2, message = "Name은 2글자 이상 입력해 주세요.")
    private String name;

    @Schema(title = "등록일", description = "사용자 등록일을 입력해 주세요.")
    @Past(message = "등록일은 미래 날짜를 입력할 수 없습니다.")
    private Date joinDate;
}
  • @Schema 어노테이션을 사용하여 각 필드의 설명을 추가합니다.

4) UserController에 Tag, Operation 및 ApiResponses 추가

API 엔드포인트를 정의하는 컨트롤러 클래스에 @Tag, @Operation, @ApiResponses 어노테이션을 추가하여 API 문서의 구조를 정의합니다.

@RestController
@Tag(name = "user-controller", description = "일반 사용자 서비스를 위한 컨트롤러")
public class UserController {
    private UserDaoService service;

    public UserController(UserDaoService service) {
        this.service = service;
    }

    @GetMapping("/users")
    public List<User> retrieveAllUsers() {
        return service.findAll();
    }

    @Operation(summary = "사용자 정보 조회 API", description = "사용자 ID를 이용하여 사용자 상세 정보 조회를 합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "OK !!",
            content = @Content(array = @ArraySchema(schema = @Schema(implementation = User.class)))),
        @ApiResponse(responseCode = "400", description = "BAD REQUEST !!"),
        @ApiResponse(responseCode = "404", description = "NOT FOUND !!"),
        @ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR !!")
    })
    public List<User> retrieveAllUsers() {
        return service.findAll();
    }
}
  • @Tag: 컨트롤러에 대한 설명을 추가합니다.

  • @Operation: 특정 API 엔드포인트에 대한 설명을 작성합니다.

  • @ApiResponses: 가능한 응답 코드와 그 설명을 작성합니다.

  • 위의 단계를 통해 Swagger를 사용하여 Spring Boot 애플리케이션에서 RESTful API 문서를 자동으로 생성하고 관리할 수 있습니다.

  • 이제 애플리케이션을 실행하면 http://localhost:8088/swagger-ui/index.html 경로에서 API 문서를 확인할 수 있습니다.

5. Spring Boot Actuator를 이용한 모니터링 및 Metrics 수집

  • Spring Boot Actuator 는 애플리케이션의 모니터링 및 메트릭 수집을 위한 강력한 도구입니다.
  • 이를 통해 애플리케이션의 상태를 모니터링하고 다양한 메트릭을 수집
  • 아래에서 Spring Boot Actuator 를 설정하고 사용하는 방법을 설명합니다.

1. Actuator 의존성 추가

먼저 pom.xml 파일에 Actuator 의존성을 추가합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2. Actuator 엔드포인트 활성화

  • application.properties 또는 application.yml 파일에서 Actuator 엔드포인트를 활성화합니다.
  • 여기서는 모든 엔드포인트를 활성화하는 설정을 추가합니다.

application.properties

management.endpoints.web.exposure.include=*

application.yml

management:
  endpoints:
    web:
      exposure:
        include: "*"

3. 보안 설정 (Optional)

  • Spring Security 를 사용하는 경우, Actuator 엔드포인트 에 대한 접근을 허용하도록 보안 설정을 추가해야 합니다.

SecurityConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/swagger-ui.html/**", "/swagger-ui/**", "/v3/api-docs/**", "/actuator/**").permitAll()
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
        return http.build();
    }
}

4. Actuator 엔드포인트 접근

애플리케이션이 정상적으로 실행되면 브라우저에서 Actuator 엔드포인트에 접근하여 애플리케이션 상태와 메트릭을 확인할 수 있습니다.

  • 전체 Actuator 엔드포인트 목록: http://localhost:8088/actuator
  • Health 엔드포인트: http://localhost:8088/actuator/health

예시

브라우저에서 http://localhost:8088/actuator에 접근하면 다음과 같은 JSON 응답을 받을 수 있습니다.

{
    "_links": {
        "self": {
            "href": "http://localhost:8088/actuator",
            "templated": false
        },
        "health": {
            "href": "http://localhost:8088/actuator/health",
            "templated": false
        },
        ...
    }
}

또한 http://localhost:8088/actuator/health에 접근하면 애플리케이션의 건강 상태를 확인할 수 있습니다.

{
    "status": "UP",
    "components": {
        "db": {
            "status": "UP",
            "details": {
                "database": "H2",
                "result": 1
            }
        },
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 499963174912,
                "free": 123456789,
                "threshold": 10485760
            }
        },
        "ping": {
            "status": "UP"
        }
    }
}
  • 이와 같이 Spring Boot Actuator를 통해 애플리케이션의 상태를 쉽게 모니터링할 수 있습니다.
  • 더 나아가 PrometheusGrafana 같은 도구와 연동하여 메트릭을 수집하고 시각화할 수 있습니다.

6. HAL Explorer

  • HAL ExplorerAPI의 리소스와 메타 데이터를 쉽게 탐색할 수 있게 해주는 도구입니다.
  • HAL(Hypertext Application Language)REST API 응답에 링크와 관련 메타 데이터를 포함시켜, 클라이언트가 응답 내의 링크를 따라가며 관련 데이터를 탐색할 수 있게 해줍니다.
  • Spring Data REST 와 함께 HAL Explorer 를 설정하면, API 탐색이 훨씬 용이해집니다.
  • 아래는 HAL ExplorerSpring Boot 프로젝트에 설정하고 사용하는 방법입니다.

1. HAL Explorer 의존성 추가

먼저, pom.xml 파일에 HAL Explorer 의존성을 추가합니다.

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-rest-hal-explorer</artifactId>
</dependency>

2. HAL Explorer 설정

  • HAL Explorer는 별도의 설정 없이 Spring Boot에서 자동으로 설정됩니다.
  • 의존성을 추가한 후 애플리케이션을 재시작하면 HAL Explorer가 활성화됩니다.

3. HAL Explorer 사용

  • HAL Explorer를 사용하려면 브라우저에서 http://localhost:8088에 접속하면 됩니다.

  • 이전에 Spring Boot Actuator를 설정한 경우, HAL Explorer 에서 Actuator 엔드포인트도 탐색할 수 있습니다.

  • 기본 HAL Explorer URL: http://localhost:8088

  • Actuator 엔드포인트 탐색: http://localhost:8088/actuator

4. 예시

HAL Explorer를 통해 API를 탐색할 때, API 응답은 다음과 같이 링크와 메타 정보를 포함한 형태로 제공됩니다.

JSON 응답 예시

{
  "_links": {
    "self": {
      "href": "http://localhost:8088"
    },
    "actuator": {
      "href": "http://localhost:8088/actuator"
    },
    "users": {
      "href": "http://localhost:8088/users"
    }
  }
}

HAL Explorer 화면

  • 브라우저에서 http://localhost:8088로 접속하면 다음과 같은 HAL Explorer 화면을 볼 수 있습니다.
  • 여기서 링크를 추가하면 해당 리소스에 대한 세부 정보를 탐색할 수 있습니다.
    • 예를 들어, /users 링크를 추가하면 사용자 리소스에 대한 정보를 볼 수 있습니다.
  • 추가로, HAL ExplorerSpring HATEOAS를 사용하여 API의 탐색성과 문서화 수준을 높일 수 있습니다.
  • 이를 통해 다른 개발자들이 API를 더 쉽게 사용하고 이해할 수 있게 됩니다.

7. Spring Security

  • Spring Security 는 Spring 기반 애플리케이션의 보안(인증 및 권한 부여)을 처리하는 강력한 프레임워크입니다.
  • 이를 통해 REST API 를 보호하고, 인증된 사용자만 특정 리소스에 접근할 수 있도록 설정할 수 있습니다.
  • 아래는 Spring Security 를 사용하여 REST API 에 보안을 추가하는 방법입니다.

1. Spring Security 의존성 추가

  • 먼저, pom.xml 파일에 Spring Security 의존성을 추가합니다.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 기본 보안 설정

  • Spring Security 의존성을 추가하면, 기본적으로 모든 엔드포인트가 보호되며 애플리케이션 시작 시 콘솔에 기본 생성된 사용자 이름(user)과 패스워드가 출력됩니다.

3. 콘솔에서 생성된 패스워드 확인

  • 애플리케이션을 실행하면 콘솔 로그에 아래와 같은 메시지가 출력됩니다.
// (예시)
Using generated security password: d4c60b68-8d92-4b27-8a57-123456789abc

이 패스워드는 기본 사용자(user)의 패스워드로 사용됩니다.

4. REST API 호출 시 인증 처리

  • 보호된 REST API 엔드포인트에 접근하려고 하면, 인증이 필요합니다.
  • Postman과 같은 클라이언트를 사용하여 인증을 처리할 수 있습니다.

Postman에서 인증 설정

  1. Postman에서 요청을 구성합니다.
  2. 요청의 Authorization 탭을 클릭합니다.
  3. 유형으로 Basic Auth를 선택합니다.
  4. Username 필드에 user를 입력합니다.
  5. Password 필드에 콘솔에 출력된 패스워드를 입력합니다.
  6. 설정을 저장하고 요청을 전송합니다.

5. Spring Security 설정 클래스 추가 (Optional)

  • 기본 설정 외에, 추가적인 보안 설정이 필요하다면 설정 클래스를 작성할 수 있습니다.

SecurityConfig 클래스 작성

import org.springframework.context.annotation.Bean;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // 공용 리소스 허용
                .anyRequest().authenticated() // 그 외 모든 요청 인증 필요
            .and()
            .httpBasic(); // HTTP Basic 인증 사용
    }

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

위 설정은 /public/** 경로를 제외한 모든 요청에 대해 인증을 요구하며, HTTP Basic 인증 방식을 사용하도록 구성합니다.

6. 예시 REST API 호출

인증되지 않은 요청

GET /users HTTP/1.1
Host: localhost:8088

응답:

{
  "timestamp": "2024-05-29T11:00:00.000+00:00",
  "status": 401,
  "error": "Unauthorized",
  "message": "Unauthorized",
  "path": "/users"
}

인증된 요청

Postman에서 Basic Auth를 설정한 후 요청:

GET /users HTTP/1.1
Host: localhost:8088
Authorization: Basic dXNlcjpkNGM2MGI2OC04ZDkyLTRiMjctOGE1Ny0xMjM0NTY3ODlhYmM=

응답:

[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john.doe@example.com"
  },
  {
    "id": 2,
    "name": "Jane Doe",
    "email": "jane.doe@example.com"
  }
]
  • 이와 같이 Spring Security를 사용하면 REST API의 보안을 강화할 수 있습니다.
  • 사용자 인증을 통해 중요한 리소스에 접근할 수 있는 권한을 제한하고, 보안 문제를 예방할 수 있습니다.

8. API 사용을 위한 사용자 인증 처리 구현

  • Spring Security에서 개발자가 직접 아이디와 패스워드를 지정하여 인증을 처리하는 방법을 살펴보겠습니다.
  • 이 방법을 통해 패스워드를 하드코딩하여 사용하거나, 데이터베이스에서 사용자 정보를 가져오는 방식을 설정할 수 있습니다.

1. application.yml 설정 (주석처리)

  • 먼저, 이전에 사용한 application.yml 설정을 주석 처리합니다.
# security:
#   user:
#     name: username
#     password: passw0rd

2. SecurityConfig 클래스 작성

  • SecurityConfig 클래스에서 사용자 정보를 설정하고, 패스워드를 인코딩하여 처리하도록 합니다.

SecurityConfig 클래스

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.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();

        UserDetails user = User.withUsername("user")
                .password(passwordEncoder().encode("passw0rd"))
                .authorities("ROLE_USER")
                .build();

        userDetailsService.createUser(user);
        return userDetailsService;
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}

3. 인증 처리

  • 이제 SecurityConfig 클래스에서 정의한 사용자 정보를 사용하여 인증을 처리할 수 있습니다.
  • Postman이나 웹 브라우저를 통해 인증된 요청을 보내보겠습니다.

Postman에서 인증 설정

  1. Postman에서 요청을 구성합니다.
  2. 요청의 Authorization 탭을 클릭합니다.
  3. 유형으로 Basic Auth를 선택합니다.
  4. Username 필드에 user를 입력합니다.
  5. Password 필드에 passw0rd를 입력합니다.
  6. 설정을 저장하고 요청을 전송합니다.

4. 예시 REST API 호출

인증된 요청

Postman에서 Basic Auth를 설정한 후 요청:

GET /users HTTP/1.1
Host: localhost:8088
Authorization: Basic dXNlcjpwYXNzdzByZA==

응답:

[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john.doe@example.com"
  },
  {
    "id": 2,
    "name": "Jane Doe",
    "email": "jane.doe@example.com"
  }
]

5. 데이터베이스에서 사용자 정보 가져오기

  • 실제 운영 환경에서는 사용자 정보를 하드코딩하지 않고, 데이터베이스에서 가져오는 방식이 더 안전하고 유연합니다.
  • 이를 구현하기 위해서는 다음과 같은 추가 설정이 필요합니다.

UserDetailsService 구현

import org.springframework.beans.factory.annotation.Autowired;
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.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Bean
    public UserDetailsService userDetailsService() {
        JdbcUserDetailsManager userDetailsService = new JdbcUserDetailsManager();
        userDetailsService.setDataSource(dataSource);
        return userDetailsService;
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}

데이터베이스 테이블 생성

CREATE TABLE users (
    username VARCHAR(50) NOT NULL PRIMARY KEY,
    password VARCHAR(100) NOT NULL,
    enabled BOOLEAN NOT NULL
);

CREATE TABLE authorities (
    username VARCHAR(50) NOT NULL,
    authority VARCHAR(50) NOT NULL,
    FOREIGN KEY (username) REFERENCES users(username)
);

사용자 데이터 삽입

INSERT INTO users (username, password, enabled) VALUES ('user', '{bcrypt}$2a$10$DowJdqkjlzplM9o.kV9xue5eThwV8F3Je4/vTi.3c9HxYRtj2.BSm', TRUE);
INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER');
  • 위의 설정을 통해 데이터베이스에서 사용자 정보를 가져와 인증을 처리할 수 있습니다.
  • 이렇게 하면 사용자 정보 변경 시 서버를 재가동할 필요 없이, 데이터베이스에서 직접 변경할 수 있습니다.
profile
안녕하세요. wony입니다.

0개의 댓글