GN2.Business 3.0.0

dotnet add package GN2.Business --version 3.0.0
                    
NuGet\Install-Package GN2.Business -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.Business" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GN2.Business" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="GN2.Business" />
                    
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.Business --version 3.0.0
                    
#r "nuget: GN2.Business, 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.Business@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.Business&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=GN2.Business&version=3.0.0
                    
Install as a Cake Tool

GN2.Business

GN2 인증서버(OpenIddict)를 사용하는 클라이언트 측 라이브러리입니다. API 서버와 응용 프로그램이 인증·인가와 서비스 간 호출을 최소한의 코드로 구성하도록 돕습니다.

  • Target Framework: net10.0 · Version: 3.0.0 · NuGet: GN2.Business
  • 의존성: GN2.Core, Microsoft.AspNetCore.Authentication.JwtBearer

Swagger, API 버저닝, EF Core 감사 확장은 GN2.Common.Web 에 있습니다.

구성

Protocol/          OIDC 통신 — 디스커버리 조회, 토큰 요청
  ProtocolResponse.cs               응답 기반 (IsError, Error, Raw, Json)
  ProtocolRequest.cs                요청 기반 + 그랜트별 요청 타입
  TokenResponse.cs
  DiscoveryDocumentResponse.cs
  HttpClientProtocolExtensions.cs   HttpClient 확장 메서드

Authentications/   ASP.NET Core 구성
  ExtendAuthentication.cs           JwtBearer 등록, 프록시 헤더
  ExtendAuthorization.cs            정책 등록, RequireGn2Roles
  ExtendApiClient.cs                HttpClient 등록
  ExtendClaimsPrincipal.cs          클레임 조회
  ClientCredentialsTokenProvider.cs 토큰 발급 · 캐시
  IdentityClientCredentialHandler.cs 토큰 자동 부착
  RoleTypes.cs / AuthorizationConsts.cs / IdentityClientConsts.cs

설정

{
  "Identity": {
    "BaseUrl": "https://auth.example.com",     // Authority (토큰 발급자)
    "IdentityUrl": "https://auth.example.com", // 토큰 발급 요청 대상
    "Audience": "example-api",
    "Scope": "example-api",
    "ClientId": "example-service",
    "ClientSecret": "..."
  }
}

IdentityConfiguration(검증용)과 IdentityClientConfiguration(발급용) 모두 GN2.Core.Configurations 에 있습니다.


1. 인증 · 인가 등록

var identity = builder.Configuration.GetSection("Identity").Get<IdentityConfiguration>()!;

builder.Services.RegisterAuthentication(identity);
builder.Services.RegisterAuthorization(identity);

var app = builder.Build();

app.AddForwardHeaders();   // 리버스 프록시를 쓴다면 인증 미들웨어보다 먼저
app.UseAuthentication();
app.UseAuthorization();

RegisterAuthentication 이 하는 일:

  • Authority 와 Audience 설정
  • MapInboundClaims = false — 이걸 켜두면(ASP.NET Core 기본값) 토큰의 sub·role 이 WS-Federation URI 로 바뀌어 JwtClaimTypes 상수로 찾을 수 없게 됩니다
  • NameClaimType = "sub", RoleClaimType = "role"
  • Authority 가 https 면 메타데이터 HTTPS 요구, http 면 해제

세부 조정이 필요하면 세 번째 인자로 JwtBearerOptions 를 직접 손봅니다.

builder.Services.RegisterAuthentication(identity, options =>
{
    options.TokenValidationParameters.ClockSkew = TimeSpan.FromSeconds(30);
});

2. 정책 사용

[Authorize(Policy = AuthorizationConsts.ManagerPolicy)]   // Manager 또는 Admin
public class ProductController : ControllerBase { }
정책 통과 역할
AdministrationPolicy Admin
ManagerPolicy Manager, Admin
LocalManagerPolicy LocalManager 이상
UserPolicy User, PrimaryUser, LocalManager 이상

모든 정책은 scope 클레임에 Audience 가 포함되어 있는지 확인한 뒤, role · client_role · ClaimTypes.Role 중 하나가 요구 역할과 일치하는지 검사합니다.

역할 체계가 다르면 정책을 직접 정의합니다.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Billing",
        policy => policy.RequireGn2Roles(identity.Audience, "BillingAdmin", "Admin"));
});

3. 서비스 간 호출 (client_credentials)

var client = builder.Configuration.GetSection("Identity").Get<IdentityClientConfiguration>()!;

builder.Services.AddIdentityCredentialClient(client);
public class OrderService(IHttpClientFactory factory)
{
    private readonly HttpClient _http = factory.CreateClient(IdentityClientConsts.ClientCredentialName);

    public Task<HttpResponseMessage> GetAsync() => _http.GetAsync("/api/v1/orders");
}
  • 토큰과 디스커버리 결과를 만료 60초 전까지 캐시합니다. 요청마다 인증서버를 부르지 않습니다.
  • 동시 요청이 몰려도 발급은 한 번만 일어납니다.
  • 401 을 받으면 캐시를 버리고 재전송이 안전한 요청에 한해 한 번 재시도합니다. 스트리밍 본문처럼 다시 읽을 수 없는 요청은 캐시만 비우고 401 을 그대로 돌려줍니다.

인증서버나 대상 API 가 여러 개인 경우

clientName 을 다르게 주면 각각 독립된 토큰 캐시를 가집니다.

builder.Services.AddIdentityCredentialClient(orderConfig, "order-api");
builder.Services.AddIdentityCredentialClient(billingConfig, "billing-api");

var http = factory.CreateClient("order-api");

만료 여유 시간과 시각 고정

builder.Services.AddIdentityCredentialClient(client, expirationSkew: TimeSpan.FromSeconds(120));

// 테스트에서는 TimeProvider 를 DI 에 등록하면 토큰 캐시가 그것을 사용합니다.
services.AddSingleton<TimeProvider>(fakeTimeProvider);

4. 사용자 토큰 전달 (on-behalf-of)

현재 요청의 Bearer 토큰을 그대로 하위 API 로 넘깁니다.

builder.Services.AddApiClient(new ExternalApiConfiguration { BaseUrl = "https://inner-api.example.com" });

var http = factory.CreateClient(IdentityClientConsts.ClientAuthenticationName);

5. 클레임 조회

ClaimsPrincipal 확장이므로 HTTP 컨텍스트 없이도 씁니다.

var userId = User.GetUserId();          // sub
var roles  = User.GetRoles();
var ok     = User.HasAnyRole("Admin", "Manager");
var scoped = User.HasScope("example-api");

IHttpContextAccessor 오버로드도 그대로 있습니다.

accessor.GetCurrentUserId();
accessor.GetCurrentRoles();

6. 프로토콜 직접 사용

등록 확장을 쓰지 않고 디스커버리·토큰을 직접 다룰 때 사용합니다.

using GN2.Business.Protocol;

using var discovery = await http.GetDiscoveryDocumentAsync("https://auth.example.com");

if (discovery.IsError)
{
    logger.LogError("디스커버리 실패: {Error}", discovery.Error);
    return;
}

using var token = await http.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address      = discovery.TokenEndpoint,
    ClientId     = "example-service",
    ClientSecret = secret,
    Scope        = "example-api"
});

if (!token.IsError)
{
    Console.WriteLine(token.AccessToken);
}
  • 예외를 던지지 않습니다. 네트워크 오류든 프로토콜 오류든 IsError 로 판정합니다.
  • 응답은 IDisposable 이므로 using 으로 받으세요. 본문은 이미 읽어두었으므로 폐기 후에도 속성은 읽을 수 있습니다.
  • HTTPS 를 기본 요구합니다. 루프백은 허용하며, 사설망이라면 요청의 RequireHttps = false 로 해제합니다.
ErrorType 의미
None 정상
Protocol 응답 본문에 error 필드 (예: invalid_client)
Http HTTP 오류인데 프로토콜 오류 본문이 없음
Exception 네트워크 오류 등. Exception 속성 참조

제공 요청 타입: ClientCredentialsTokenRequest, AuthorizationCodeTokenRequest, RefreshTokenRequest, PasswordTokenRequest


2.x → 3.0.0 마이그레이션

2.x 3.0.0
GN2Secret.JwtAuthKey 제거됨. 하드코딩 키였으므로 값을 교체하고 설정으로 옮기세요
using Duende.IdentityModel; using GN2.Core.Identity;
GN2.Identity.Protocol 패키지 폐지됨. GN2.Business.Protocol 네임스페이스로 통합
HttpClientTokenRequestExtensions HttpClientProtocolExtensions
RegisterSwaggerForIdentity, RegisterVersioning, RegisterApiServer GN2.Common.Web.Swagger / .Extends
UseSwaggerVersion, UseRefuseSearchEngine GN2.Common.Web.Extends
RegisterDataProtection<T> GN2.Common.Web.EntityFramework
AuditableEntity*Extensions GN2.Common.Web.EntityFramework
Swagger 필터 4종 GN2.Common.Web.Swagger

동작 변경:

  • AddApiClient · AddIdentityCredentialClientIHttpClientBuilder 를 반환합니다. 핸들러를 추가로 체이닝할 수 있습니다.
  • 두 메서드 모두 잘못된 주소를 등록 시점에 ArgumentException 으로 거부합니다.
  • 디스커버리·토큰 요청이 HTTPS 를 요구합니다 (루프백 예외).
  • ProtocolResponseIDisposable 입니다.

라이선스

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.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on GN2.Business:

Package Downloads
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 126 8/22/2026
2.1.3 134 6/3/2026
2.1.2 130 3/26/2026
2.1.1 123 3/26/2026
2.1.0 189 3/11/2026
2.0.7 126 3/6/2026
2.0.6 131 3/3/2026
2.0.5 143 3/2/2026
2.0.4 132 3/2/2026
2.0.3 128 3/2/2026
2.0.2 129 3/2/2026
2.0.1 134 3/2/2026
2.0.0 127 3/2/2026
1.4.7 267 10/20/2025
1.4.6 230 10/20/2025
1.4.5 224 10/20/2025
1.4.4 220 10/20/2025
1.4.3 226 10/19/2025
1.4.2 234 10/19/2025
1.4.1 242 10/19/2025
Loading failed

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

구성
- OIDC 프로토콜 통신(디스커버리 · 토큰 요청)을 이 패키지의 GN2.Business.Protocol 네임스페이스로 통합했습니다. 별도 패키지였던 GN2.Identity.Protocol 은 폐지되었습니다.
- 패키지 범위를 인증서버 클라이언트 전용으로 축소했습니다. Swagger 필터, API 버저닝, EF Core 감사 확장, DataProtection 등록은 GN2.Common.Web 으로 이동했습니다.
- 의존성이 Swashbuckle / Asp.Versioning / EntityFrameworkCore / System.IdentityModel.Tokens.Jwt 없이 JwtBearer 하나로 줄었습니다.
- 330줄짜리 ExtendAuthentication 을 관심사별로 분리했습니다: ExtendAuthentication(인증), ExtendAuthorization(인가), ExtendApiClient(클라이언트 등록), ExtendClaimsPrincipal(클레임 조회).

보안
- 하드코딩된 키를 담고 있던 GN2Secret 클래스를 제거했습니다. 이전 버전의 값을 사용 중이라면 반드시 교체하세요.
- 인가 정책의 연산자 우선순위 오류로 클레임 타입과 무관하게 값이 역할명과 일치하기만 하면 통과하던 문제를 수정했습니다.
- 디스커버리 · 토큰 요청에 HTTPS 를 기본 요구합니다. 루프백 주소는 개발 편의를 위해 허용하며, 요청의 RequireHttps 로 해제할 수 있습니다.
- 클레임 이름 매핑을 껐습니다(MapInboundClaims = false, NameClaimType = sub, RoleClaimType = role).

정확성
- 토큰 캐시의 토큰과 만료 시각을 불변 객체로 묶어 참조 단위로 교체합니다. 잠금 밖에서 읽을 때 둘이 어긋난 조합을 볼 수 있던 문제를 없앴습니다.
- 401 재시도가 본문을 다시 읽을 수 없는 요청까지 재전송하던 문제를 수정했습니다. 이제 본문이 없거나 버퍼링된 요청만 재시도합니다.
- 프로토콜 응답이 HttpResponseMessage 를 해제하지 않던 문제를 수정했습니다(IDisposable 구현).
- 잘못된 주소·빈 ClientId 등을 등록 시점에 검증합니다.

기능
- 명명된 클라이언트별 키 기반 등록으로 여러 인증서버 · 대상 API 를 동시에 사용할 수 있습니다.
- 클레임 조회를 ClaimsPrincipal 확장으로 제공해 HTTP 컨텍스트 없이도 사용할 수 있습니다. 기존 IHttpContextAccessor 메서드는 그대로 유지됩니다.
- RequireGn2Roles 로 기본 4단계 외의 역할 체계를 지원합니다.
- 토큰 만료 여유 시간과 TimeProvider 를 주입할 수 있습니다.

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