GN2.Core 3.0.0

dotnet add package GN2.Core --version 3.0.0
                    
NuGet\Install-Package GN2.Core -Version 3.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GN2.Core" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GN2.Core" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="GN2.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GN2.Core --version 3.0.0
                    
#r "nuget: GN2.Core, 3.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GN2.Core@3.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GN2.Core&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=GN2.Core&version=3.0.0
                    
Install as a Cake Tool

GN2.Core

GN2 계열 .NET 시스템의 공유 커널입니다. 인증서버(OpenIddict)와 모든 클라이언트가 함께 참조하는, 가장 아래 계층의 라이브러리입니다.

  • Target Framework: net10.0 · Version: 3.0.0 · NuGet: GN2.Core
  • 외부 NuGet 의존성 없음

설계 원칙

  1. 의존성 0 — 어떤 프로젝트가 참조해도 전이 의존성이 생기지 않습니다.
  2. I/O 없음 — 네트워크·파일·DB에 접근하지 않습니다. HttpClient를 쓰는 코드는 이 패키지에 두지 않습니다 (GN2.Business 담당).
  3. 프레임워크 중립 — ASP.NET Core, EF Core, Swagger에 의존하지 않습니다.
  4. 트리밍 · Native AOT 호환

패키지 관계

GN2.Core                도메인 · 계약 · 프로토콜 상수
  ├─ GN2.Business          OIDC 통신 + ASP.NET Core 인증 · 인가
  ├─ GN2.Common.Library    암호화, 메일, ActionBridge
  └─ GN2.Common.Web        Swagger, API 버저닝, EF Core 확장

OpenIddict 인증서버 → GN2.Core 만 참조하면 됩니다.

구성

Identity/        JwtClaimTypes, OidcConstants
Models/          ReturnValue, ReturnValues, AuditableEntity, BaseEntity, ConditionStatus
Models/Paging/   PagingBase, PagingParameter, SearchParameter
Configurations/  ExternalApi / Site / Identity / SMTP 설정 레코드
Abstracts/       IHasAuditableEntity, IPagingBase
Extends/         Are, ExtendObject, ExtendQueryable, JsonHelper
Helpers/         DateTimeHelper, StringHelper, ValidateHelper
ErrorHandling/   RestException
Filters/         StringValueAttribute

Identity — 서버와 클라이언트의 단일 출처

JwtClaimTypesOidcConstants의 값은 OpenIddict의 OpenIddictConstants 및 관련 RFC와 일치합니다.

using GN2.Core.Identity;

// 인증서버 (OpenIddict)
identity.AddClaim(JwtClaimTypes.Role, "Admin")
        .SetDestinations(OidcConstants.Destinations.AccessToken);

options.RegisterScopes(OidcConstants.Scopes.OpenId,
                       OidcConstants.Scopes.Profile,
                       OidcConstants.Scopes.OfflineAccess);

// 클라이언트
var subject = user.FindFirst(JwtClaimTypes.Subject)?.Value;
var roles   = user.FindAll(JwtClaimTypes.Role).Select(c => c.Value);

OidcConstants 안에 GrantTypes, Scopes, Destinations, CodeChallengeMethods, ResponseTypes, ResponseModes, Prompts, ClientAuthenticationMethods, TokenTypeHints, Algorithms, Parameters, Errors, Discovery, Endpoints가 있습니다.

⚠️ 클레임 이름 매핑을 반드시 끄세요

JwtBearerOptions.MapInboundClaims는 **기본값이 true**라서, 토큰의 sub·role이 WS-Federation URI로 바뀐 채 들어옵니다. 그러면 위의 FindFirst(JwtClaimTypes.Role)이 아무것도 찾지 못합니다.

options.MapInboundClaims = false;
options.TokenValidationParameters.NameClaimType = JwtClaimTypes.Subject;
options.TokenValidationParameters.RoleClaimType = JwtClaimTypes.Role;

GN2.BusinessRegisterAuthentication은 이 설정을 기본으로 적용합니다.

JwtClaimTypes.ClientRole("client_role")은 표준이 아니라 Duende IdentityServer 관례입니다. OpenIddict에는 대응 개념이 없습니다.

감사 상태 — 행위 메서드로 전이

setter를 직접 건드리지 마세요. 아래 메서드가 상태·사용여부·작업자·시각을 한 번에 갱신합니다.

var condition = AuditableEntity.Create(userId);   // 생성

condition.MarkUpdated(userId);   // 수정
condition.MarkDraft(userId);     // 초안 (Hidden)
condition.Publish(userId);       // 공개 (Active)
condition.Disable(userId);       // 비활성 (Disabled)
condition.MarkDeleted(userId);   // 논리 삭제 (Out)
condition.Restore(userId);       // 복구

condition.IsPublicVisible;       // IsEnabled && Status == Active
condition.IsDraft;
condition.IsRemoved;

시각은 UTC로 기록합니다. 테스트에서 고정하려면 TimeProvider를 넘기세요.

condition.MarkDeleted(userId, fakeTimeProvider);
ConditionStatus 의미
None 0 미정 (운영 데이터에 사용하지 않음)
Active 1 공개 · 활성
Disabled 2 비활성
Hidden 3 숨김 · 초안
Out 4 논리 삭제

EF Core 매핑과 상태별 조회 필터는 GN2.Common.Web.EntityFramework에 있습니다.

응답 계약

var result = new ReturnValues<Order>();

try
{
    result.SetSuccess(1, await repository.GetAsync(id));
}
catch (Exception ex)
{
    result.SetError(ex);
    logger.LogError(ex, "{Diag}", result.ToDiagnosticString());
}

팩토리도 있습니다.

return order is null
    ? ReturnValues<Order>.Fail("주문을 찾을 수 없습니다.", errorCode: 404)
    : ReturnValues<Order>.Ok(order);

Message호출자에게 노출되는 값입니다. 예외 객체는 직렬화되지 않는 Exception 속성에만 담기므로 스택 트레이스가 응답으로 새지 않습니다.

페이징 계약

public record OrderSearch : SearchParameter
{
    public string? Status { get; init; }
}

var items = await query
    .WhereIf(!string.IsNullOrWhiteSpace(p.Keyword), x => x.Title.Contains(p.Keyword!))
    .Skip((p.CurPage - 1) * p.PageSize)
    .Take(p.PageSize)
    .ToListAsync();

페이지 번호 블록과 이동 URL(PagingHelper)은 GN2.Common.Web.Models.Paging에 있습니다.

트리밍 · Native AOT

패키지 전체가 IsAotCompatible로 빌드되며 경고가 없습니다. 리플렉션을 쓰는 두 곳만 명시적으로 표시되어 있습니다.

  • ExtendObject[DynamicallyAccessedMembers]로 필요한 멤버를 보존
  • JsonHelper.Serialize/Deserialize<T>[RequiresUnreferencedCode] 표시. AOT 게시 시에는 JsonTypeInfo<T> 오버로드를 쓰세요
var json = JsonHelper.Serialize(order, AppJsonContext.Default.Order);

2.x → 3.0.0 마이그레이션

다른 패키지로 이동

2.x 3.0.0
TokenResponse, DiscoveryDocumentResponse, ProtocolResponse, *TokenRequest, HttpClientTokenRequestExtensions GN2.Business.Protocol
SwaggerConfiguration GN2.Common.Web.Configurations
PagingHelper, ExtendParameters GN2.Common.Web.Models.Paging
IPagingHelper GN2.Common.Web.Abstracts
GN2.Core.Abstracts.IHasAuditableEntity GN2.Core
GN2.Core.Models.Paging.SearchParameter GN2.Core
Duende.IdentityModel.JwtClaimTypes GN2.Core.Identity.JwtClaimTypes

이름 변경

2.x 3.0.0
AuthenticationSchemes.AuthorizationHeaderBearer / ~Basic AuthenticationSchemes.Bearer / .Basic
EndpointAuthenticationMethods ClientAuthenticationMethods
TokenErrors Errors
Endpoints.Revocation = connect/revocation connect/revoke
JwtClaimTypes.ScopeSeparator OidcConstants.Separator
JwtClaimTypes.IdentityTokenHint OidcConstants.Parameters.IdTokenHint
ExtendObject.toDualList ToDualList

제거

AzureBlobSettings, ApplicationInsights, RedisConfiguration, HostSettings, DatabaseConnectionStrings, ClientConfiguration, SiteInfo, EntityHelper, FileHelper, RandomHelper, CalendarHelper, StringHelper.GetYoutubeThumbnailURL

RandomHelperSystem.Random 기반이라 토큰·인증 코드 생성에 쓰면 안 되는 물건이었습니다. 보안 용도라면 RandomNumberGenerator를 쓰세요.

동작 변경

  • ReturnValue.SetError(Exception)이 더 이상 스택 트레이스를 Message에 넣지 않습니다 → ToDiagnosticString() 사용
  • ReturnValues<T>에서 Data를 설정하지 않는 SetSuccess 오버로드는 컴파일 경고가 납니다
  • ReturnValues<T>(T data) 생성자가 이제 데이터를 저장합니다
  • StringHelper.SpaceSplitList가 중복 값에서 예외를 던지지 않습니다

버전 정책

SemVer를 따릅니다. ConditionStatus의 숫자 값은 영속화되므로 변경하지 않습니다.

3.0.0 배포 후 GN2.Core.csprojEnablePackageValidation 주석을 해제하면, 그 시점부터 공개 API를 깨는 변경이 빌드 오류로 잡힙니다.

라이선스

Apache License 2.0

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on GN2.Core:

Package Downloads
GN2.Business

GN2 인증서버(OpenIddict 기반)를 사용하는 클라이언트 — API 서버와 응용 프로그램 — 가 인증·인가와 서비스 간 호출을 최소한의 코드로 구성하도록 돕는 패키지입니다. Protocol — 디스커버리 문서 조회와 OAuth 2.0 토큰 요청을 HttpClient 확장으로 제공합니다. 예외를 던지지 않고 모든 실패를 IsError 로 표현하며, 시크릿이 평문으로 나가지 않도록 HTTPS 를 기본 요구합니다(루프백 예외). Authentication — RegisterAuthentication 한 줄로 JwtBearer 검증을 등록합니다. 클레임 이름 매핑을 꺼서 인증서버와 클라이언트가 GN2.Core.Identity.JwtClaimTypes 의 같은 상수를 그대로 사용합니다. Authorization — RegisterAuthorization 으로 Admin/Manager/LocalManager/User 4단계 기본 정책을 등록하거나, RequireGn2Roles 로 서비스 고유의 역할 체계에 맞춰 직접 구성합니다. 스코프 검사는 문자열을 할당하지 않는 방식으로 수행합니다. Clients — AddIdentityCredentialClient 로 client_credentials 토큰을 자동 부착하는 HttpClient 를 등록합니다. 토큰과 디스커버리 결과를 만료까지 캐시하고, 401 응답 시 재전송이 안전한 요청에 한해 한 번 재시도합니다. 명명된 클라이언트별로 독립된 캐시를 가지므로 인증서버가 여러 개여도 함께 사용할 수 있습니다. AddApiClient 는 현재 요청의 Bearer 토큰을 하위 API 로 그대로 전달합니다. 의존성은 GN2.Core 와 Microsoft.AspNetCore.Authentication.JwtBearer 뿐입니다. Swagger, API 버저닝, EF Core 같은 서버 측 구성은 GN2.Common.Web 에 있습니다.

GN2.Common.Library

GN2.Core 를 사용하는 프로젝트가 반복해서 구현하는 일들을 모아둔 범용 유틸리티 패키지입니다. 웹 프레임워크에 의존하지 않으므로 API 서버, 워커, 콘솔 앱에서 똑같이 사용할 수 있습니다. Bridge — 요청 하나에 핸들러 하나를 대응시키는 경량 디스패처입니다. 어셈블리를 스캔해 핸들러를 등록하고, IBridgeBehavior 파이프라인으로 로깅 · 검증 · 트랜잭션 같은 횡단 관심사를 핸들러 밖에서 처리합니다. 요청 타입마다 강타입 디스패처를 한 번만 만들어 캐시합니다. Mapping — 이름과 타입이 맞는 속성은 규약으로 복사하고, 필요한 속성만 ForMember 로 지정하는 경량 매퍼입니다. 매핑 계획을 타입 쌍마다 한 번만 계산합니다. Security — AES-256-GCM 인증 암호화(ISecretProtector), PBKDF2-HMAC-SHA512 비밀번호 해시(IPasswordHasher), 무결성 확인용 해시 · HMAC, Base64Url 인코딩을 제공합니다. 모두 DI 로 주입받아 사용하며 전역 상태가 없습니다. Mail — 다중 수신자 · 참조 · 숨은참조 · HTML/평문 본문 · 취소 토큰을 지원하는 SMTP 발송기입니다. 본문과 주소를 로그에 남기지 않습니다. Text — 저장된 HTML 에서 평문 · 이미지 주소를 추출하거나 요약 문구를 만드는 헬퍼입니다. 의존성은 GN2.Core 와 Microsoft.Extensions 추상화 세 개뿐입니다. Swagger, MVC, EF Core 같은 웹 구성은 GN2.Common.Web 에, 인증서버 연동은 GN2.Business 에 있습니다.

GN2.Common.Web

GN2 인증서버(OpenIddict 기반)를 사용하는 ASP.NET Core Web API 를 최소한의 코드로 구성하기 위한 패키지입니다. 컨트롤러 · JSON · API 버저닝 · 인증 · 인가 · CORS · Swagger · 예외 처리 · 헬스체크를 한 번에 등록합니다. 부트스트랩 — RegisterWebApi 와 UseWebApi 두 줄이면 API 서버가 구성됩니다. IdentityConfiguration 을 넘기면 GN2.Business 의 JwtBearer 인증과 4단계 역할 정책이 함께 등록되고, 파이프라인 순서(ForwardedHeaders → 예외 처리 → CORS → Swagger → 인증 → 인가 → 엔드포인트)도 알아서 맞춰집니다. 세부 제어가 필요하면 개별 Register/Use 메서드를 직접 조합할 수 있습니다. Swagger — API 버전마다 문서를 하나씩 만들고, 인증서버의 Authorization Code + PKCE 흐름을 Swagger UI 의 Authorize 버튼에 연결합니다. XML 주석 포함, [Authorize] 오퍼레이션의 401/403 표기, api-version 파라미터 정리를 기본 제공합니다. 오류 응답 — 처리되지 않은 예외와 모델 검증 실패를 RFC 7807 ProblemDetails 로 통일합니다. GN2.Core 의 RestException 은 예외에 담긴 상태 코드로 응답하며, 스택 트레이스는 개발 환경에서만 노출됩니다. 컨트롤러 — BaseApiController 가 ReturnValue · ReturnValues<T> 를 HTTP 결과로 변환하는 헬퍼와 현재 사용자 · 역할 · 스코프 조회, 페이징 헤더 출력을 제공합니다. EF Core — AuditableEntity 소유 타입 매핑과 공개/관리자 조회 필터, DataProtection 키의 DbContext 저장을 제공합니다. 유틸 — 절대 URL 생성, 업로드 파일의 안전한 확장자 · 파일명 생성, 페이징 번호 블록 계산.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.0 151 8/22/2026
2.0.7 127 6/3/2026
2.0.6 141 4/5/2026
2.0.5 146 3/26/2026
2.0.4 135 3/2/2026
2.0.3 245 2/8/2026
2.0.2 219 1/11/2026
2.0.1 131 1/11/2026
2.0.0 250 12/27/2025
1.1.4 417 10/11/2025
1.1.3 154 10/11/2025
1.1.2 412 10/2/2025
1.1.1 499 8/21/2025
1.1.0 246 8/16/2025
1.0.0 297 8/3/2025

3.0.0 (호환성 없는 변경 포함)

계층 정리
- 네트워크 I/O 를 GN2.Business 로 분리했습니다. GN2.Core 는 이제 도메인·계약·상수만 담으며 HttpClient 를 사용하지 않습니다. 토큰을 발급하는 인증서버는 GN2.Core 만 참조하면 됩니다.
- 이동한 타입: DiscoveryDocumentResponse, TokenResponse, ProtocolResponse, ProtocolRequest 계열, HttpClientTokenRequestExtensions → GN2.Business (GN2.Business.Protocol 네임스페이스)
- SwaggerConfiguration, PagingHelper, IPagingHelper → GN2.Common.Web

Identity
- Duende.IdentityModel 의존성을 제거하고 GN2.Core.Identity 로 대체했습니다.
- OidcConstants 를 OpenIddict 대응 수준으로 확장했습니다: Scopes, Destinations, CodeChallengeMethods, ResponseTypes, ResponseModes, Prompts, ClientAuthenticationMethods, ClientAssertionTypes, TokenTypeHints, Algorithms, Parameters, Errors
- JwtClaimTypes.ClientRole 은 Duende 관례임을 문서화했습니다. OpenIddict 에는 대응 개념이 없습니다.
- JwtBearerOptions.MapInboundClaims 기본값(true)이 클레임 이름을 바꿔 상수 매칭을 깨뜨리는 문제를 문서화했습니다. GN2.Business 의 RegisterAuthentication 은 매핑을 끕니다.

도메인 모델
- AuditableEntity 에 상태 전이 메서드(MarkCreated, MarkUpdated, MarkDeleted, Disable, MarkDraft, Publish, Restore)와 TimeProvider 지원을 추가했습니다. 상태·사용여부·작업자·시각이 한 번에 갱신되어 불일치가 생기지 않습니다.
- IsPublicVisible, IsRemoved, IsDraft 계산 속성을 추가했습니다.

보안 · 버그 수정
- ReturnValue.SetError(Exception) 이 스택 트레이스를 Message 에 넣어 API 응답으로 유출될 수 있던 문제를 수정했습니다. 예외는 직렬화되지 않는 Exception 속성에 보관하고, 진단 문자열이 필요하면 ToDiagnosticString() 을 사용합니다.
- ReturnValues<T> 에서 Data 없이 성공 상태를 만들 수 있던 오버로드에 경고를 붙였습니다.
- ReturnValues<T>(T data) 생성자가 데이터를 무시하던 문제를 수정했습니다.
- StringHelper.SpaceSplitList 가 중복 값에서 예외를 던지던 문제를 수정했습니다.

정리
- 특정 인프라에 종속되거나 사용되지 않던 API 제거: AzureBlobSettings, ApplicationInsights, RedisConfiguration, HostSettings, DatabaseConnectionStrings, ClientConfiguration, SiteInfo, EntityHelper, FileHelper, RandomHelper, CalendarHelper
- 네임스페이스 통일: IHasAuditableEntity, SearchParameter 가 GN2.Core 로 이동
- 트리밍 · AOT 호환성 표시. 리플렉션을 사용하는 ExtendObject 와 JsonHelper 에는 DynamicallyAccessedMembers / RequiresUnreferencedCode 를 명시했고, JsonHelper 에 JsonTypeInfo 오버로드를 추가했습니다.
- XML 문서 파일, Source Link, 심볼 패키지(snupkg) 포함

전체 변경 내역: https://github.com/gn2studio/GN2/releases