基于Swashbuckle.AspNetCore的自定义认证配置问题咨询
You’re absolutely right—Swagger UI and Swashbuckle don’t have built-in support for this specific HMAC-based authentication flow that requires three coordinated headers. But instead of using hidden fields, the better approach is to extend Swagger UI with custom JavaScript that dynamically generates the required X-API-SIGN and X-API-TIMESTAMP headers when a request is sent. Here’s how to implement it:
Step 1: Define a Custom Security Scheme in Swashbuckle
First, we need to tell Swagger about our custom authentication headers so the UI knows to display an input for the static X-API-KEY (since the other two are generated dynamically). Add this to your Swagger configuration (in Program.cs or Startup.cs):
builder.Services.AddSwaggerGen(c => { // ... other Swagger config (like title, version) ... // Define the custom security scheme for our API key c.AddSecurityDefinition("CustomHmacAuth", new OpenApiSecurityScheme { Type = SecuritySchemeType.ApiKey, Name = "X-API-KEY", In = ParameterLocation.Header, Description = "Enter your shared API key. The X-API-SIGN and X-API-TIMESTAMP headers will be auto-generated." }); // Apply this security scheme to all endpoints c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "CustomHmacAuth" } }, new string[] {} } }); });
Step 2: Add Custom JavaScript to Swagger UI
Next, we’ll inject a JavaScript snippet into Swagger UI that intercepts requests, generates the timestamp and HMAC signature, and adds the missing headers. This replaces the need for hidden fields entirely—everything happens dynamically when the user clicks "Try it out".
First, add this configuration when setting up Swagger UI:
app.UseSwaggerUI(c => { // ... other UI config (like specifying Swagger JSON endpoint) ... // Inject our custom JavaScript file c.InjectJavascript("/swagger-custom.js"); });
Then create a swagger-custom.js file in your wwwroot directory with this code:
// Wait for Swagger UI to fully load before modifying it window.addEventListener('load', async function() { const ui = window.ui; // Intercept every request right before it's sent ui.getConfigs().requestInterceptor = async function(request) { // Grab the API key the user entered in Swagger UI const apiKey = ui.getAuthorizations()['CustomHmacAuth']?.value; if (!apiKey) return request; // Skip if no key is provided // Generate a timestamp (match the format your backend expects—here we use Unix epoch in seconds) const timestamp = Math.floor(Date.now() / 1000).toString(); request.headers['X-API-TIMESTAMP'] = timestamp; // Build the data string to sign—this must exactly match how your backend constructs it const signatureData = [ apiKey, timestamp, request.method, request.url.split('?')[0], // Get the endpoint path without query parameters request.body || '' // Include request body if present (ensure it's the same as what's sent) ].join('|'); // Generate HMAC SHA256 signature using the Web Crypto API const encoder = new TextEncoder(); const key = await window.crypto.subtle.importKey( 'raw', encoder.encode(apiKey), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); const signatureBuffer = await window.crypto.subtle.sign('HMAC', key, encoder.encode(signatureData)); const signature = btoa(String.fromCharCode(...new Uint8Array(signatureBuffer))); // Add the generated signature to the request headers request.headers['X-API-SIGN'] = signature; return request; }; });
Key Things to Adjust:
- Signature Data Format: Double-check that the
signatureDataconcatenation (order, separator, included fields) exactly matches what your backend uses to verify the signature. If your server uses a different separator or excludes certain fields, tweak this part. - Request Body Handling: If your API requires signing the raw request body, ensure
request.bodyin the JS matches the exact payload sent to the server. Swagger UI might format JSON bodies differently, so you may need to stringify it consistently. - Browser Support: The Web Crypto API works in all modern browsers. If you need to support older ones, swap it out with a library like
crypto-jsfor HMAC generation.
Why This Beats Hidden Fields
This approach is cleaner and more secure:
- No messy DOM manipulation or hidden fields to manage
- Timestamps are always fresh (generated at request time)
- The API key stays in memory rather than being stored in the DOM
内容的提问来源于stack exchange,提问作者Joe Phillips

