GN2.Core
3.0.0
dotnet add package GN2.Core --version 3.0.0
NuGet\Install-Package GN2.Core -Version 3.0.0
<PackageReference Include="GN2.Core" Version="3.0.0" />
<PackageVersion Include="GN2.Core" Version="3.0.0" />
<PackageReference Include="GN2.Core" />
paket add GN2.Core --version 3.0.0
#r "nuget: GN2.Core, 3.0.0"
#:package GN2.Core@3.0.0
#addin nuget:?package=GN2.Core&version=3.0.0
#tool nuget:?package=GN2.Core&version=3.0.0
GN2.Core
GN2 계열 .NET 시스템의 공유 커널입니다. 인증서버(OpenIddict)와 모든 클라이언트가 함께 참조하는, 가장 아래 계층의 라이브러리입니다.
- Target Framework:
net10.0· Version:3.0.0· NuGet:GN2.Core - 외부 NuGet 의존성 없음
설계 원칙
- 의존성 0 — 어떤 프로젝트가 참조해도 전이 의존성이 생기지 않습니다.
- I/O 없음 — 네트워크·파일·DB에 접근하지 않습니다.
HttpClient를 쓰는 코드는 이 패키지에 두지 않습니다 (GN2.Business담당). - 프레임워크 중립 — ASP.NET Core, EF Core, Swagger에 의존하지 않습니다.
- 트리밍 · 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 — 서버와 클라이언트의 단일 출처
JwtClaimTypes와 OidcConstants의 값은 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.Business의 RegisterAuthentication은 이 설정을 기본으로 적용합니다.
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
RandomHelper는System.Random기반이라 토큰·인증 코드 생성에 쓰면 안 되는 물건이었습니다. 보안 용도라면RandomNumberGenerator를 쓰세요.
동작 변경
ReturnValue.SetError(Exception)이 더 이상 스택 트레이스를Message에 넣지 않습니다 →ToDiagnosticString()사용ReturnValues<T>에서Data를 설정하지 않는SetSuccess오버로드는 컴파일 경고가 납니다ReturnValues<T>(T data)생성자가 이제 데이터를 저장합니다StringHelper.SpaceSplitList가 중복 값에서 예외를 던지지 않습니다
버전 정책
SemVer를 따릅니다. ConditionStatus의 숫자 값은 영속화되므로 변경하지 않습니다.
3.0.0 배포 후 GN2.Core.csproj의 EnablePackageValidation 주석을 해제하면, 그 시점부터 공개 API를 깨는 변경이 빌드 오류로 잡힙니다.
라이선스
Apache License 2.0
| Product | Versions 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. |
-
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