【问题标题】:How to modify token endpoint response body with Owin OAuth2 in Asp.Net Web API 2如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文
【发布时间】:2015-04-23 18:49:10
【问题描述】:

我想从令牌端点响应中修改响应正文。

我尝试使用 MessageHandler 拦截 /Token 请求,但它不起作用。

我可以通过覆盖OAuthAuthorizationServerProvider.TokenEndpoint方法向响应中添加一些附加信息,但我无法创建自己的响应正文。

有没有办法拦截/Token请求?


编辑

我发现了如何从令牌端点响应中删除响应正文内容,如下所示:HttpContext.Current.Response.SuppressContent = true;

这似乎是实现我的目标的正确方法,但现在当我使用context.AdditionalResponseParameters.Add() 方法添加我的自定义信息时,SuppressContent 会阻止任何更改。

现在我有这样的东西:

// Removing the body from the token endpoint response
HttpContext.Current.Response.SuppressContent = true;
// Add custom informations
context.AdditionalResponseParameters.Add("a", "test");

【问题讨论】:

    标签: asp.net asp.net-web-api oauth-2.0 owin http-token-authentication


    【解决方案1】:

    要简单地将新项目添加到 JSON 令牌响应,您可以使用 TokenEndpointResponse 而不是 TokenEndpoint 通知。


    如果您正在寻找一种方法来将 OAuth2 授权服务器准备的令牌响应完全替换为您自己的,那么遗憾的是没有简单的方法可以做到这一点,因为 OAuthAuthorizationServerHandler.InvokeTokenEndpointAsync 在之后不会检查 OAuthTokenEndpointContext.IsRequestCompleted 属性调用TokenEndpointResponse 通知。

    https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerHandler.cs

    这是一个已知问题,但是当我建议修复它时,将其包含在 Katana 3 中为时已晚。

    您应该尝试一下Owin.Security.OpenIdConnect.Server:它是专为 Katana 3.0 和 4.0 设计的 OAuthAuthorizationServerMiddleware 的一个分支。

    https://www.nuget.org/packages/Owin.Security.OpenIdConnect.Server/1.0.2

    当然,它包括允许绕过默认令牌请求处理的正确检查(这甚至是我在 fork 时修复的第一件事)。

    【讨论】:

    【解决方案2】:

    你几乎就在那里 +Samoji @Samoji 并且真的帮助/启发了我得到答案。

    // Add custom informations
    context.AdditionalResponseParameters.Add("a", "test");
    // Overwrite the old content
    var newToken = context.AccessToken;
    context.AdditionalResponseParameters.Add("access_token", newToken);
    

    我发现它只是用我的新令牌替换了我的旧令牌。

    【讨论】:

      【解决方案3】:

      这个问题类似于How to extend IdentityServer4 workflow to run custom code

      因此您可以创建自定义中间件并在 Startup 中的 OAuth2 服务之前注册它:

          public void Configuration(IAppBuilder app)
          {
              ....
              app.Use(ResponseBodyEditorMiddleware.EditResponse);
      
              app.UseOAuthAuthorizationServer(...);
              ...
          }
      

      自定义中间件在哪里:

          public static async Task EditResponse(IOwinContext context, Func<Task> next)
          {
              // 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();
      
              // get a body as string
              var bodyString = Encoding.UTF8.GetString(buffer.GetBuffer());
      
              // make some changes to the body
              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;
          }
      

      【讨论】:

        【解决方案4】:

        如果您想在请求到达管道中的 IControllerFactory 处理程序后避免这样做,最好的拦截请求和响应的方法是通过 MessageHandler - 显然在这种情况下使用自定义“属性”

        我过去使用过MessageHandlers来拦截对api/token的请求,创建一个新的请求并获取响应,创建一个新的响应。

            protected override async Task<HttpResponseMessage> SendAsync(
                HttpRequestMessage request, CancellationToken cancellationToken)
            {
                //create a new auth request
                var authrequest = new HttpRequestMessage();
                authrequest.RequestUri = new Uri(string.Format("{0}{1}", customBaseUriFromConfig, yourApiTokenPathFromConfig));
        
                //copy headers from the request into the new authrequest
                foreach(var header in request.Headers)
                {
                    authrequest.Headers.Add(header.Key, header.Value);
                }
        
                //add authorization header for your SPA application's client and secret verification
                //this to avoid adding client id and secret in your SPA
                var authorizationHeader =
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}", _clientIdFromConfig, _secretKeyFromConfig)));
        
                //copy content from original request
                authrequest.Content = request.Content;
        
                //add the authorization header to the client for api token
                var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(request.Headers.Authorization.Scheme, authorizationHeader);
                var response = await client.PostAsync(authrequest.RequestUri, authrequest.Content, cancellationToken);
        
                if(response.StatusCode == HttpStatusCode.OK)
                {
                    response.Headers.Add("MyCustomHeader", "Value");
                    //modify other attributes on the response
                }
        
                return response;
            }
        

        这非常适合我。但是,WebApiConfig.cs 文件中需要此处理程序的配置(如果您使用的是 ASP.NET MVC,则为 RouteConfig.cs)。

        您能否详细说明在处理程序上对您不起作用的是什么?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-10-28
          • 1970-01-01
          • 2014-10-05
          • 1970-01-01
          • 2013-11-30
          • 2018-01-11
          • 2018-09-28
          • 1970-01-01
          相关资源
          最近更新 更多