LMS License SDK for .NET
C# / .NET 8 환경에서 Licensify 라이선스를 검증하고 세션을 유지하기 위한 클라이언트 SDK입니다. ECDH P-256 + AES-128-GCM + HMAC-SHA256 기반 보안 채널을 자동으로 구성합니다.
설치
dotnet add package LmsLicenseSDK
요구 사항: .NET 8.0 이상
빠른 시작
using LmsLicenseSDK;
using LmsLicenseSDK.Models;
var client = new LicenseClient();
LicenseSession session;
try
{
session = await client.VerifyAsync(
licenseKey: "XXXX-XXXX-XXXX-XXXX",
appId: "your-app-id",
clientVersion: "1.0.0");
}
catch (LicenseException ex)
{
Console.WriteLine($"인증 실패: {ex.ErrorCode} ({ex.ServerCode}) - {ex.Message}");
return;
}
// 세션이 만료/오류로 종료될 때 알림 받기
session.SessionTerminated += (_, ex) =>
Console.WriteLine($"세션 종료: {ex.ErrorCode} - {ex.Message}");
// 서버가 내려준 변수 읽기
var token = session.GetGlobalVariable("apiToken");
// 앱 종료 시 명시적 release (권장)
await session.ReleaseAsync();
SDK는 30초 간격으로 자동 하트비트를 보내고, 세션 키를 회전시킵니다. 사용자는 별도 설정이 필요 없습니다.
API 레퍼런스
LicenseClient
| 멤버 | 설명 |
|---|---|
new LicenseClient() | 인스턴스 생성 |
Task<LicenseSession> VerifyAsync(licenseKey, appId, clientVersion, ct) | 라이선스 검증 후 세션 반환. 실패 시 LicenseException |
LicenseSession
| 멤버 | 설명 |
|---|---|
string SessionId | 세션 식별자 |
DateTime ExpiresAt | 세션 만료 시각 (UTC) |
long RemainingMs | 남은 시간 (밀리초) |
string? LatestVersion | 서버가 알려준 최신 버전 (있을 때) |
string? DownloadUrl | 최신 버전 다운로드 URL (있을 때) |
event EventHandler<LicenseException> SessionTerminated | 세션이 비정상 종료되면 발생 |
IReadOnlyCollection<string> LocalVariableKeys | 로컬 변수 키 목록 |
IReadOnlyCollection<string> GlobalVariableKeys | 글로벌 변수 키 목록 |
JsonElement? GetLocalVariable(string) | 로컬 변수 조회 |
JsonElement? GetGlobalVariable(string) | 글로벌 변수 조회 |
void SetLocalVariable(string, JsonElement) | 로컬 변수 설정 (메모리에 암호화 저장) |
void SetGlobalVariable(string, JsonElement) | 글로벌 변수 설정 (메모리에 암호화 저장) |
Task ReleaseAsync() | 세션 해제 (서버 알림 + 키 소거) |
Dispose() / DisposeAsync() | using 패턴 지원 |
에러 처리
검증 실패는 모두 LicenseException으로 통일됩니다. ErrorCode enum으로 분기하세요.
try
{
session = await client.VerifyAsync(licenseKey, appId, clientVersion);
}
catch (LicenseException ex)
{
switch (ex.ErrorCode)
{
case ErrorCode.LicenseExpired:
// 만료 안내 화면
break;
case ErrorCode.UnsupportedVersion:
// 업데이트 유도, ex.LatestVersion / ex.DownloadUrl 활용
break;
case ErrorCode.LicenseAlreadyInUse:
// 다른 기기에서 사용 중
break;
default:
// 일반 오류 안내
break;
}
}
ErrorCode 매핑
| ErrorCode | 서버 코드 | 의미 |
|---|---|---|
InternalServerError | SDK_001 | 서버 내부 오류 |
InvalidRequest | SDK_002 | 요청 형식 오류 |
SoftwareNotFound | SDK_003 | App ID 미등록 |
LicenseNotFound | SDK_004 | 라이선스 키 없음 |
InvalidFileHash | SDK_005 | 실행 파일 해시 불일치 |
UnsupportedVersion | SDK_006 | 지원하지 않는 클라이언트 버전 |
LicenseAlreadyInUse | SDK_101 | 다른 세션이 점유 중 |
LicenseBanned | SDK_102 | 차단된 라이선스 |
LicenseExpired | SDK_103 | 만료된 라이선스 |
SoftwareBanned | SDK_201 | 차단된 소프트웨어 |
SoftwareInactive | SDK_202 | 비활성 상태 |
SoftwareSuspended | SDK_203 | 일시 정지 |
SoftwareMaintenance | SDK_204 | 점검 중 |
SoftwareUnsupported | SDK_205 | 지원 종료 |
SessionExpired | SDK_301 | 세션 만료 |
Unknown | — | 그 외 (네트워크/암호화 오류 포함) |
LicenseException 부가 정보
상황에 따라 다음 속성이 채워집니다.
| 속성 | 채워지는 경우 |
|---|---|
LatestVersion | UnsupportedVersion |
DownloadUrl | UnsupportedVersion |
Until | SoftwareSuspended, SoftwareMaintenance 등 일시 차단 |
Reason | 운영자가 사유를 등록한 경우 |
동작 방식 (요약)
- SDK는 ECDH P-256 키쌍을 즉석 생성해 서버 공개키와 공유 비밀을 도출합니다.
- 공유 비밀로 1회용 wrapping key를 만들어 서버가 발급한 세션 키(서명 + 암호화 분리)를 풉니다.
- 이후 모든 응답 페이로드는 AES-128-GCM으로 암호화되고 HMAC-SHA256으로 무결성 검증됩니다.
- 30초 간격 하트비트 시 세션 키가 새것으로 회전됩니다.
Release호출 또는Dispose시 키를 즉시 메모리에서 소거합니다.
모든 변수(
LocalVariable/GlobalVariable)는 메모리상에서도 평문으로 보관되지 않으며, 조회 시점에만 복호화됩니다.
자주 묻는 질문
Q. 동기 API는 없나요?
권장하지 않습니다. ASP.NET 환경에서 데드락 위험이 있어 모든 호출은 async로 제공합니다.
Q. 하트비트 주기를 바꿀 수 있나요? SDK가 정책으로 강제하므로 변경할 수 없습니다.
Q. 로그를 보고 싶어요. SDK는 향후 자체 로그를 서비스로 전송하며, 운영자는 서비스 홈페이지에서 확인할 수 있습니다 (지원 예정).
Q. 실행 파일 해시 검증이 실패해요.
SDK는 실행 파일의 SHA-256을 자동 계산해 전송하며, 운영자가 해당 버전에 등록한 해시와 일치하지 않으면 SDK_005로 거절됩니다.
- 빌드가 바뀌었다면 운영자에게 새 해시 등록을 요청하세요.
- 해시를 등록하지 않은 버전은 해시 검증을 건너뜁니다(다른 검증은 그대로 수행).
- 계산 자체가 실패하는 환경(권한 등)에서는 서버 정책에 따라 처리됩니다.
라이선스 / 지원
- 패키지: NuGet
- 문의: 운영팀 또는 Q&A 게시판