Search code examples
c#asp.net-coreswashbuckleswagger-codegenswashbuckle.aspnetcore

Encode parameter before executing the request


We are using .NET Core 3.1 and Swashbuckle.AspNetCore 5.6.3.

Some of our controller actions require User-Identity HTTP header to be sent in the request. The value of this User-Identity HTTP header is base64-encoded JSON object. Example:

JSON object

{
  "email": "test@test.com"
}

is encoded in base64 as:

ewogICJFbWFpbCI6ICJ0ZXN0QHRlc3QuY29tIgp9.

We implemented the following filter operation which checks if controller action has [RequireUserIdentityFilterAttribute] attribute and adds a parameter accordingly.

public class RequireUserIdentityOperationFilter : IOperationFilter
{
  public void Apply(OpenApiOperation operation, OperationFilterContext context)
  {
    // check if controller action has RequireUserIdentityFilterAttribute with reflection
    var hasRequireUserIdentityFilterAttribute = context.MethodInfo
      .GetCustomAttributes(true)
      .OfType<RequireUserIdentityFilterAttribute>()
      .Any();

    if (hasRequireUserIdentityFilterAttribute)
    {
      operation.Parameters.Add(new OpenApiParameter
      {
        Description = "Base-64 encoded user email object. Example: { \"Email\": \"test@test.com\" } => ewogICJFbWFpbCI6ICJ0ZXN0QHRlc3QuY29tIgp9",
        Name = "User-Identity",
        In = ParameterLocation.Header,
        Schema = new OpenApiSchema
        {
          Type = "string",
          Example = new OpenApiString("ewogICJFbWFpbCI6ICJ0ZXN0QHRlc3QuY29tIgp9")
        }
      });
    }
  }
}

This is how it looks like in SwaggerUI:

image

It works fine as-is. User-Identity header is sent to the server.

However, it is not very user-friendly because user has to input a string which must be base64-encoded. Is it possible that we simplify the input so that the user will only have to input user email (ex. test@test.com) and C# will handle the base64 encoding before the request is sent to the server?


Solution

  • SwaggerUI uses JavaScript to send the requests to the server. You could inject a script that intercepts the request and changes the header before transmitting it to the server, e.g.

    app.UseSwaggerUI(c =>
    {
        // ...
        var adjustHeaders = @"(request) => {
            let header = request.headers["User-Identity"];
            if (header && header.length > 0) {
              // header is a JSON object
              if (header[0] == "{") header = 
                btoa(header);
              // header is an email address
              else if (header.indexOf("@") >= 0) 
                header = btoa(JSON.stringify({ email: header }));
              // Otherwise assume that it is already encoded
              request.headers["User-Identity"] = header;
            }
            return request;
        }";
        c.UseRequestInterceptor(adjustHeaders);
    });
    

    Above script is a pseudo-Javascript that can give you a starting point. Please test it in the browser whether it works in your situation and for the browsers your SwaggerUI targets.