반응형

여러 사이트가 하나의 서버에서 운영되고 있을 때, 사이트 간 데이터를 조회하거나 수정, 등록하려면 몇 가지 기본 원칙과 기술을 적용해야 합니다. 이를 구현하기 위해서는 API 통합, 보안 정책, 인증 및 권한 관리와 같은 요소들을 철저히 고려해야 합니다. 이번 글에서는 아래의 예제를 기반으로 구현 방법과 주요 고려사항을 상세히 설명합니다.


요구사항 분석

예시 상황

  • 하나의 서버에서 여러 사이트를 운영 중:
  • 각 사이트는 독립적으로 작동하지만, 데이터를 서로 조회하고 수정, 등록할 수 있어야 함.
  • 예를 들어, aa.com에서 bb.com의 데이터를 수정하거나 cc.com에서 aa.com의 화면을 조회해야 함.

주요 고려사항

  1. 데이터 교환 방식
    • 사이트 간 데이터를 안전하고 효율적으로 전달해야 함.
  2. 보안
    • 인증 및 권한 관리를 통해 데이터 접근을 제한.
  3. 유지보수성
    • 구조를 단순화하여 유지보수를 쉽게 해야 함.
  4. 확장성
    • 추가 사이트가 생겨도 쉽게 확장 가능해야 함.

구현 방법

1. 데이터 교환 방식 선택

다음과 같은 방식 중 하나를 선택할 수 있습니다.

(1) RESTful API

  • 각 사이트는 데이터를 공개할 API를 구축하여 서로 호출.
  • 예를 들어, http://bb.com에 데이터 조회 API를 구현하면 http://aa.com에서 이를 호출하여 데이터를 얻음.

(2) GraphQL

  • 데이터를 효율적으로 쿼리할 수 있는 방식.
  • 단일 엔드포인트에서 필요한 데이터만 선택적으로 조회 가능.

(3) 서버 간 HTTP 요청

  • 각 서버 간에 HTTP 요청을 직접 전송하여 데이터를 주고받음.

(4) 데이터베이스 공유

  • 모든 사이트가 동일한 데이터베이스를 사용하도록 설정.
  • 데이터 교환이 필요 없지만, 각 사이트에서 접근 권한 및 논리를 관리해야 함.

2. RESTful API 구현 예제

API 설계

각 사이트에서 데이터를 조회, 수정, 삭제하기 위한 API를 RESTful 방식으로 설계합니다.

1) API 엔드포인트 설계

다음은 http://bb.com에서 사용할 API 엔드포인트 예시입니다.

  • 데이터 조회: GET /api/data
    • 입력: id (선택)
    • 출력: 데이터 리스트 또는 특정 데이터
  • 데이터 등록: POST /api/data
    • 입력: 데이터 내용
  • 데이터 수정: PUT /api/data/{id}
    • 입력: 수정할 데이터
  • 데이터 삭제: DELETE /api/data/{id}
    • 입력: 삭제할 데이터 ID

Spring Boot로 REST API 구현

다음은 Spring Boot로 구현한 간단한 REST API 예제입니다.

Controller 클래스

@RestController
@RequestMapping("/api/data")
public class DataController {

    // 임시 데이터 저장소
    private final Map<Integer, String> dataStore = new HashMap<>();
    private int currentId = 1;

    // 데이터 조회
    @GetMapping
    public ResponseEntity<List<String>> getData(@RequestParam(required = false) Integer id) {
        if (id == null) {
            return ResponseEntity.ok(new ArrayList<>(dataStore.values()));
        } else {
            String data = dataStore.get(id);
            return data != null ? ResponseEntity.ok(Collections.singletonList(data)) 
                                : ResponseEntity.notFound().build();
        }
    }

    // 데이터 등록
    @PostMapping
    public ResponseEntity<String> addData(@RequestBody String newData) {
        dataStore.put(currentId++, newData);
        return ResponseEntity.ok("Data added successfully");
    }

    // 데이터 수정
    @PutMapping("/{id}")
    public ResponseEntity<String> updateData(@PathVariable int id, @RequestBody String updatedData) {
        if (dataStore.containsKey(id)) {
            dataStore.put(id, updatedData);
            return ResponseEntity.ok("Data updated successfully");
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    // 데이터 삭제
    @DeleteMapping("/{id}")
    public ResponseEntity<String> deleteData(@PathVariable int id) {
        if (dataStore.remove(id) != null) {
            return ResponseEntity.ok("Data deleted successfully");
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}

3. 클라이언트에서 다른 사이트 호출하기

RestTemplate 사용 예제

Spring Boot의 RestTemplate을 사용하여 다른 사이트의 데이터를 호출할 수 있습니다.

클라이언트 코드 예제 (aa.com에서 bb.com 호출)

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ApiClient {

    private final RestTemplate restTemplate;

    public ApiClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String getDataFromBbCom() {
        String url = "http://bb.com/api/data";
        ResponseEntity response = restTemplate.getForEntity(url, String.class);
        return response.getBody();
    }
}

4. 보안 및 인증 구현

JWT (JSON Web Token) 기반 인증

각 사이트 간 호출 시, JWT를 활용해 인증을 처리합니다.

JWT 토큰 생성

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JwtUtil {

    private static final String SECRET_KEY = "mySecretKey";

    public static String generateToken(String subject) {
        return Jwts.builder()
                   .setSubject(subject)
                   .setIssuedAt(new Date())
                   .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1시간 유효
                   .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                   .compact();
    }
}

JWT 검증

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

public class JwtValidator {

    private static final String SECRET_KEY = "mySecretKey";

    public static Claims validateToken(String token) {
        return Jwts.parser()
                   .setSigningKey(SECRET_KEY)
                   .parseClaimsJws(token)
                   .getBody();
    }
}

5. 서버 간 호출 흐름 예제

  1. aa.com에서 bb.com 호출:
    • aa.com이 JWT를 생성하여 요청 헤더에 포함.
    • bb.com은 요청을 수신하여 JWT를 검증한 후 데이터 반환.
  2. 헤더에 토큰 추가
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + JwtUtil.generateToken("aa.com"));

HttpEntity entity = new HttpEntity<>(headers);

ResponseEntity response = restTemplate.exchange(
        "http://bb.com/api/data",
        HttpMethod.GET,
        entity,
        String.class
);

6. 데이터베이스 공유 방식

  • 여러 사이트가 동일한 데이터베이스를 사용하는 경우, 단일 DB를 기반으로 필요한 데이터를 직접 조회하거나 변경합니다.
  • 각 사이트는 논리적으로 다른 테이블이나 스키마를 사용하거나, 테이블에 사이트 구분 컬럼을 추가합니다.

예시: 사이트 구분 컬럼

CREATE TABLE site_data (
    id INT PRIMARY KEY,
    site_id VARCHAR(10),
    data_content TEXT
);

-- 특정 사이트 데이터만 조회
SELECT * FROM site_data WHERE site_id = 'aa';

결론

사이트 간 데이터를 안전하고 효율적으로 공유하려면 RESTful API, 인증 체계, 데이터베이스 설계 등 다양한 기술을 통합적으로 고려해야 합니다.
이번 글에서는 API 중심의 구현 방법과 보안 방안을 설명했으며, 필요에 따라 GraphQL 또는 단일 데이터베이스 접근 방식을 적용할 수 있습니다.
이를 통해 여러 사이트를 통합적으로 관리하면서도 독립성을 유지할 수 있는 강력한 시스템을 설계할 수 있습니다.

반응형

+ Recent posts