شماره مستند: TECH-XIDS-APIKEY-001
نسخه: ۱.۰
تاریخ تهیه: ۲۰ مهر ۱۴۰۵
طبقه‌بندی: داخلی - فنی

راهنمای جامع پیاده‌سازی و عیب‌یابی احراز هویت XApiKey

پروژه xIds (Identity Server) | ماژول مدیریت Application و API Key

۱

مقدمه و بررسی وضعیت فعلی

در پروژه xIds، زیرساخت کاملی برای مدیریت XApplication و XApiKey پیاده‌سازی شده است. کلاس‌های XApplicationProvider و XApiKeyHelper وظیفه تولید، هش کردن و اعتبارسنجی کلیدها را بر عهده دارند. با این حال، چالش اصلی در لایه Authentication Middleware و نحوه اتصال آن به Policyهای موجود بود.

مشکل شناسایی شده: درخواست‌های ارسالی با هدر X-Api-Key توسط ASP.NET Core نادیده گرفته می‌شدند، زیرا Scheme پیش‌فرض روی JWT Bearer تنظیم شده بود و Handler مخصوص ApiKey فراخوانی نمی‌شد.
۲

راه‌حل فنی: اصلاح زنجیره احراز هویت

برای رفع مشکل، دو تغییر اساسی در فایل xIds/DI/XDIHelperExtension.cs اعمال شد:

الف) ثبت Scheme اختصاصی برای XApiKey

قبل از ثبت JwtBearer، Scheme مربوط به ApiKey ثبت می‌شود تا در لیست Authentication Schemes وجود داشته باشد.

ب) استفاده از ForwardDefaultSelector هوشمند

به جای استفاده ثابت از ForwardDefault، از یک Delegate استفاده می‌کنیم که Header درخواست را بررسی می‌کند.

// xIds/DI/XDIHelperExtension.cs public static void AddXIdentityServerAuthentication( this IServiceCollection services, IConfiguration configuration, bool addApiKeyAuthentication = false) { services.AddXIdentityResourceConfiguration(configuration); var authBuilder = services.AddAuthentication(); // 1. ثبت Scheme برای XApiKey (اولویت اول) if (addApiKeyAuthentication) { authBuilder.AddScheme<AuthenticationSchemeOptions, XApiKeyAuthenticationHandler>( XAuthenticationScheme.XApiKey.GetStringValue(), // "XApiKey" options => { }); } // 2. ثبت JwtBearer با Selector هوشمند authBuilder.AddJwtBearer(options => { options.SaveToken = true; options.RequireHttpsMetadata = false; // انتخاب دینامیک Scheme بر اساس هدر درخواست options.ForwardDefaultSelector = context => { var apiKeyHeader = XHeader.ApiKey.GetStringValue(); // "X-Api-Key" if (context.Request.Headers.ContainsKey(apiKeyHeader)) { return XAuthenticationScheme.XApiKey.GetStringValue(); } // در غیر این صورت، از احراز هویت استاندارد IdentityServer استفاده کن return XAuthentication.IDENTITY_SERVER_LOCAL_API; }; }) .AddLocalApi(); }
۳

اصلاح Claims تولید شده در Handler

در فایل xIds/Providers/XApiKeyAuthenticationHandler.cs، متد HandleAuthenticateAsync باید Claimهای صحیح را تولید کند تا با Policyهای تعریف شده در XAuthorizationHelper همخوانی داشته باشد.

نکته مهم: Policyهای ApiKey بر اساس Scope (مانند read, write, admin) کار می‌کنند، نه Role. بنابراین Claim از نوع JwtClaimTypes.Scope ضروری است.
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { // ... استخراج و اعتبارسنجی ApiKey ... var validationResult = await applicationProvider.ValidateApiKey(apiKey, clientIP); if (validationResult.Errors.HasChild()) return AuthenticateResult.Fail(string.Join(", ", validationResult.Errors)); var claims = new List<Claim> { new Claim(ClaimTypes.Name, validationResult.OwnerId), new Claim(JwtClaimTypes.Subject, validationResult.OwnerId), new Claim("application_id", validationResult.ApplicationId.ToString()), new Claim("auth_type", "apikey"), }; // افزودن Scopeهای مجاز به Claims if (validationResult.Scopes != null) { foreach (var scope in validationResult.Scopes) { claims.Add(new Claim(JwtClaimTypes.Scope, scope)); } } var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); }
۴

نحوه استفاده در Controllerها

برای محافظت از Endpointها با ApiKey، از Attributeهای زیر استفاده کنید:

[RequireXPowered] [Authorize(Policy = XPolicies.ApiKeyAccess)] // دسترسی کلی public async Task<ActionResult> MySecureAction() { ... } [Authorize(Policy = XPolicies.ApiKeyReadAccess)] // فقط خواندن public async Task<ActionResult> GetItems() { ... }
تست موفقیت‌آمیز: اکنون با ارسال هدر X-Api-Key: xapp_... به Endpointهای فوق، احراز هویت انجام شده و دسترسی اعطا می‌شود.
۵

چک‌لیست نهایی استقرار

ردیف اقدام وضعیت
۱ بررسی ثبت AddXIdentityServerAuthentication در Startup با پارامتر true ✅ انجام شد
۲ اطمینان از وجود Policyهای ApiKeyAccess در XAuthorizationHelper ✅ موجود است
۳ تست ایجاد ApiKey جدید از طریق /Applications/{id}/ApiKeys/Create ✅ تست شد
۴ تست دسترسی به /Account/Test/HiApiKeyAccess با کلید معتبر ✅ پاس شد