0

我有一个 OAuthServerProvider 在验证用户名和密码后发出令牌。当用户名或密码无效时,我拒绝 owin 上下文,默认情况下它将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));
    }
}

需要知道我在这里做错了什么。

4

1 回答 1

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是必不可少的,这样可以确保在调度响应头之前修改头。

但是我仍然不知道提琴手是如何获得正确的响应状态代码的。

希望它可以帮助某人。

于 2016-10-05T10:00:50.100 回答