我有一个OAuthServerProvider在验证用户名和密码后发出令牌。当用户名或密码无效时,我拒绝owin Context,默认情况下会返回400 Bad Request
作为状态代码。
但我想回复401 Unauthorized
为实现这一点,我编写了一个中间件,它将检查标题并查看是否存在自定义标头,如果存在,将用401替换状态代码。
if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey(Constants.OwinChallengeFlag))
{
var headerValues = context.Response.Headers.GetValues(Constants.OwinChallengeFlag);
context.Response.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());
context.Response.Headers.Remove(Constants.OwinChallengeFlag);
}
当我用fiddler点击它时,这个工作非常好,但是我在下面写的单元测试总是得到400.不知怎的,当我用单元测试发出请求时,跳过了中间件。
[TestFixture]
public class UnitTest1
{
private TestServer _server;
[SetUp]
public void SetUp()
{
_server = TestServer.Create<Startup>();
}
[Test]
public void ShouldReturnUnauthorizedResponse()
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "/token");
//wrong password
var requestContent = "grant_type=password&UserName=foo&Password=bar";
request.Content = new StringContent(requestContent, Encoding.UTF8, "application/x-www-form-urlencoded");
var response = _server.HttpClient.SendAsync(request).Result;
//This assert fails, but shouldn't
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized));
}
}
需要知道我在这里做错了什么。
答案 0 :(得分:0)
我终于明白了......
await _next.Invoke(environment)
是罪魁祸首。我使用相同的环境字典对象调用它,它被传递到中间件,因此对context
对象的修改没有在单元测试中反映出来。
以下代码按预期工作....
public async Task Invoke(IDictionary<string, object> environment)
{
var context = new OwinContext(environment);
var response = context.Response;
response.OnSendingHeaders(state =>
{
var resp = (OwinResponse)state;
if (resp.StatusCode == 400 && resp.Headers.ContainsKey(Constants.OwinChallengeFlag))
{
var headerValues = context.Response.Headers.GetValues(Constants.OwinChallengeFlag);
resp.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());
resp.ReasonPhrase = HttpStatusCode.Unauthorized.ToString();
resp.Headers.Remove(Constants.OwinChallengeFlag);
}
}, response);
await _next.Invoke(context.Environment);
}
除了传递从修改后的environment
对象获取的context
变量之外,修改response.OnSendingHeaders
内的响应头是必不可少的,这可以确保在调度响应Header之前修改头。
但是我仍然不知道小提琴手是如何获取正确的响应状态代码的。
希望它有所帮助。