如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文
Posted
技术标签:
【中文标题】如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文【英文标题】:How to modify token endpoint response body with Owin OAuth2 in Asp.Net Web API 2 【发布时间】: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");
【问题讨论】:
【参考方案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 时修复的第一件事)。
【讨论】:
@Alisson 在这里:github.com/aspnet/AspNetKatana/blob/dev/src/…【参考方案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.NewLineOriginal body:Environment.NewLinebodyString";
// 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("01", 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)。
您能否详细说明在处理程序上对您不起作用的是什么?
【讨论】:
以上是关于如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文的主要内容,如果未能解决你的问题,请参考以下文章
Asp.Net Web API 2第十课——使用OWIN自承载Web API
ASP.NET Web API 2:如何使用外部身份验证服务登录?
如何在使用 JWT 的 asp.net 核心 web 应用和 web api 中使用谷歌身份验证
如何在 Asp.Net Web API 2 中使用 Owin OAuth2 修改令牌端点响应正文