GN2.Business
3.0.0
dotnet add package GN2.Business --version 3.0.0
NuGet\Install-Package GN2.Business -Version 3.0.0
<PackageReference Include="GN2.Business" Version="3.0.0" />
<PackageVersion Include="GN2.Business" Version="3.0.0" />
<PackageReference Include="GN2.Business" />
paket add GN2.Business --version 3.0.0
#r "nuget: GN2.Business, 3.0.0"
#:package GN2.Business@3.0.0
#addin nuget:?package=GN2.Business&version=3.0.0
#tool nuget:?package=GN2.Business&version=3.0.0
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·AddIdentityCredentialClient가IHttpClientBuilder를 반환합니다. 핸들러를 추가로 체이닝할 수 있습니다.- 두 메서드 모두 잘못된 주소를 등록 시점에
ArgumentException으로 거부합니다. - 디스커버리·토큰 요청이 HTTPS 를 요구합니다 (루프백 예외).
ProtocolResponse가IDisposable입니다.
라이선스
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
- GN2.Core (>= 3.0.0)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.11)
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 |
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