How to extend IdentityServer4 workflow to run cust

2019-05-10 03:24发布

问题:

I have a basic Identityserver4 implementation based on the quick start sample.

In my startup I have the following:

    public void ConfigureServices(IServiceCollection services)
    {
        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer()
            .AddTemporarySigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients());
    }

    public void Configure(IApplicationBuilder app)
    {
        ...
        app.UseIdentityServer();
    }

I want to extend the IdentityServer4 workflow so that after the access token is generated I can run business logic (based on the claims in the access token) and modify the response send to the calling client. I tried creating a .NET core middleware but it seems the IdentityServer middleware short-circuits the rest of the pipeline (no middleware place after the UseIdentityServer will be executed).

Are they any extension method in Identityserver4 that I can use to always modify the response issued by IdentityServer4? I am using the credentials grant. Essentially I want to run some business logic to modify the response send to the client once IdentityServer4 is done with its workflow

回答1:

Unfortunately, there is no way to do that. When you request any IdentityServer endpoint, IdentityServer middleware short-circuits the rest of the pipeline. You can check source code: IdentityServerMiddleware class.

I believe it was done for a reason. But if you really need to modify the response, you have at least three options:

  1. Create a fork and remove return operator from IdentityServerMiddleware Invoke method (be careful to short-circuit the rest of the pipeline adding return into your last middleware).
  2. Create your own IdentityServerMiddleware, IdentityServerApplicationBuilderExtensions implementations and use them instead of default.
  3. Place your middleware before the UseIdentityServer. Your middleware should look like this:

    public ResponseBodyEditorMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task Invoke(HttpContext context)
    {
        // get the original body
        var body = context.Response.Body;
    
        // replace the original body with a memory stream
        var buffer = new MemoryStream();
        context.Response.Body = buffer;
    
        // invoke the next middleware from the pipeline
        await _next.Invoke(context);
    
        // get the body as a string
        var bodyString = Encoding.UTF8.GetString(buffer.GetBuffer());
    
        // make some changes
        bodyString = $"The body has been replaced!{Environment.NewLine}Original body:{Environment.NewLine}{bodyString}";
    
        // update the memory stream
        var bytes = Encoding.UTF8.GetBytes(bodyString);
        buffer.SetLength(0);
        buffer.Write(bytes, 0, bytes.Length);
    
        // replace the memory stream with updated body
        buffer.Position = 0;
        await buffer.CopyToAsync(body);
        context.Response.Body = body;
    }