Java (Spring Boot) 実装例
お知らせ
このドキュメントは機械翻訳で作成された下書きであり、現在レビュー中です。機械翻訳の特性上、一部の内容が不正確であったり、韓国語の原文と異なる場合があります。より正確な情報については、韓国語のドキュメントをご参照ください。
JWT エンコーダーの実装
Kollus のレスポンス仕様に合わせてヘッダーと Payload を生成し、HS256 アルゴリズムで署名するコンポーネントです。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Custom JWT Encoder for Kollus
*/
public class KollusJwtEncoder {
private final ObjectMapper objectMapper = new ObjectMapper();
public String encode(Map<String, Object> payload, String key) throws Exception {
// 1. Construct the header
Map<String, String> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
String headerJson = objectMapper.writeValueAsString(header);
String payloadJson = objectMapper.writeValueAsString(payload);
// 2. Base64Url encode (without padding)
String encodedHeader = Base64.getUrlEncoder().withoutPadding()
.encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
String encodedPayload = Base64.getUrlEncoder().withoutPadding()
.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
String unsignedToken = encodedHeader + "." + encodedPayload;
// 3. Generate HS256 signature
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmac.init(secretKey);
byte[] signatureBytes = hmac.doFinal(unsignedToken.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getUrlEncoder().withoutPadding()
.encodeToString(signatureBytes);
return unsignedToken + "." + signature;
}
}
Play Callback コントローラーの実装
Kollus サーバーからのPOSTリクエストを受信し、Play Callback の種類ごとにビジネスロジックを処理するサンプルです。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.Instant;
import java.util.*;
@SpringBootApplication
@RestController
public class KollusPlayCallbackApplication {
private static final String KOLLUS_KEY = "{CUSTOM_KEY}";
private static final String JWT_KEY = "{SECURITY_KEY}";
private final KollusJwtEncoder jwtEncoder = new KollusJwtEncoder();
/**
* Endpoint to receive play callbacks
*/
@PostMapping("/play/callback")
public ResponseEntity<String> playCallback(
@RequestParam("kind") Integer kind,
@RequestParam("client_user_id") String clientUserId,
@RequestParam("player_id") String playerId,
@RequestParam(value = "device_name", required = false) String deviceName,
@RequestParam("media_content_key") String mediaContentKey,
@RequestParam(value = "hardware_id", required = false) String hardwareId,
@RequestParam(value = "uservalues", required = false) String uservalues,
@RequestParam(value = "localtime", required = false) Long localtime) {
try {
System.out.println("Play Callback - kind: " + kind +
", user: " + clientUserId +
", media: " + mediaContentKey);
Map<String, Object> responseData;
// Logic branching by callback type (kind1: Expiration settings, kind3: Final approval)
if (kind == 1) {
responseData = processKind1(clientUserId, mediaContentKey);
} else if (kind == 3) {
responseData = processKind3(clientUserId, playerId, mediaContentKey);
} else {
responseData = createErrorResponse("Invalid kind");
}
// Sign the response data
String jwtToken = jwtEncoder.encode(responseData, JWT_KEY);
// Configure response headers (Required: X-Kollus-UserKey)
HttpHeaders headers = new HttpHeaders();
headers.set("X-Kollus-UserKey", KOLLUS_KEY);
headers.setContentType(MediaType.TEXT_PLAIN);
return ResponseEntity.ok().headers(headers).body(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("Error processing callback");
}
}
/**
* kind1 (Playback expiration settings)
*/
private Map<String, Object> processKind1(String clientUserId, String mediaContentKey) {
// TODO: Verify user and content permissions in the database
Map<String, Object> data = new HashMap<>();
data.put("result", 1);
data.put("expiration_date", Instant.now().getEpochSecond() + 86400); // 1 day
data.put("vmcheck", 1);
data.put("disable_tvout", 0);
data.put("expiration_playtime", 1800); // 30 minutes
data.put("cpcheck", 1);
Map<String, Object> response = new HashMap<>();
response.put("data", data);
response.put("exp", Instant.now().getEpochSecond() + 3600); // JWT valid for 1 hour
return response;
}
/**
* kind3 (Final playback approval)
*/
private Map<String, Object> processKind3(String clientUserId, String playerId,
String mediaContentKey) {
// TODO: Verify playback permissions and expiration status in the database
Map<String, Object> data = new HashMap<>();
data.put("result", 1);
data.put("content_expired", 0); // 0: Playable, 1: Playback blocked
Map<String, Object> response = new HashMap<>();
response.put("data", data);
response.put("exp", Instant.now().getEpochSecond() + 3600);
return response;
}
/**
* Create error response
*/
private Map<String, Object> createErrorResponse(String message) {
Map<String, Object> data = new HashMap<>();
data.put("result", 0);
data.put("message", message);
Map<String, Object> response = new HashMap<>();
response.put("data", data);
return response;
}
public static void main(String[] args) {
SpringApplication.run(KollusPlayCallbackApplication.class, args);
}
}
サンプルコードリポジトリリンク
各言語の連携サンプルコードは、以下の GitHub リポジトリで確認できます。