如何在Asp.NETWebAPI 2中使用OWINOAuth2修改令牌端点响应主体

如何在Asp.NETWebAPI 2中使用OWINOAuth2修改令牌端点响应主体,asp.net,asp.net-web-api,oauth-2.0,owin,http-token-authentication,Asp.net,Asp.net Web Api,Oauth 2.0,Owin,Http Token Authentication,我想从令牌端点响应修改响应主体 protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { //create a new auth request var authrequest = new HttpRequestMessag

我想从令牌端点响应修改响应主体

    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;
    }
我试图用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");

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


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

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

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


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

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

我过去曾使用MessageHandler拦截对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;
    }
受保护的覆盖异步任务SendAsync(
HttpRequestMessage请求,CancellationToken CancellationToken)
{
//创建新的身份验证请求
var authrequest=新的HttpRequestMessage();
authrequest.RequestUri=新Uri(string.Format(“{0}{1}”,customBaseUriFromConfig,yourApiTokenPathFromConfig));
//将请求中的标题复制到新的authrequest中
foreach(request.Headers中的var头)
{
authrequest.Headers.Add(header.Key,header.Value);
}
//为SPA应用程序的客户端和机密验证添加授权标头
//这是为了避免在SPA中添加客户id和密码
var授权标头=
Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format(“{0}:{1}”,_clientIdFromConfig,_secretKeyFromConfig));
//从原始请求复制内容
authrequest.Content=request.Content;
//将授权标头添加到api令牌的客户端
var client=新的HttpClient();
client.DefaultRequestHeaders.Authorization=新的AuthenticationHeaderValue(request.Headers.Authorization.Scheme,authorizationHeader);
var response=wait client.PostAsync(authrequest.RequestUri、authrequest.Content、cancellationToken);
if(response.StatusCode==HttpStatusCode.OK)
{
添加(“MyCustomHeader”、“Value”);
//修改响应上的其他属性
}
返回响应;
}
这对我很有效。但是,WebApiConfig.cs文件(如果使用ASP.NET MVC,则为RouteConfig.cs)中需要此处理程序的配置


你能详细说明一下什么对你不起作用吗?

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

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

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

这个问题类似于

因此,您可以在启动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;
    }
公共静态异步任务EditResponse(IOwinContext上下文,Func next)
{
//得到原始的身体
var body=context.Response.body;
//用内存流替换原始正文
var buffer=newmemoryStream();
context.Response.Body=缓冲区;
//从管道中调用下一个中间件
等待next.Invoke();
//以字符串形式获取主体
var bodyString=Encoding.UTF8.GetString(buffer.GetBuffer());
//对身体做一些改变
bodyString=$“正文已被替换!{Environment.NewLine}原始正文:{Environment.NewLine}{bodyString}”;
//更新内存流
var bytes=Encoding.UTF8.GetBytes(bodyString);
buffer.SetLength(0);
写(字节,0,字节,长度);
//用更新的正文替换内存流
缓冲器位置=0;
等待缓冲区。CopyToAsync(正文);
context.Response.Body=Body;
}
@Alisson此处: