5

所以我在 [Authorize] 标签上找到了一些启发我的点点滴滴,但没有任何东西可以解决我的问题。

我的情况是我有 Web Api 方法,我想使用 RestSharp 进行集成测试。但是 RestSharp 正在获取我的登录页面,而不是调用的结果。

[Authorize]
public Item GetItem([FromBody] int id) 
{
   return service.GetItem(id);
}

该产品使用自定义登录系统,而我真正想要的是一种仅在集成测试中禁用 [Authorize] 徽章的方法。但是我读到您可以允许匿名用户并且它会“禁用”徽章,因此在解决方案中,我有一个集成测试项目,并且在该项目中我有一个 App.config 文件。在那个文件中我放了:

 <location>
  <system.web>
   <authorization>
     <allow users="?"/>
    </authorization>
  </system.web>
 </location>

但这似乎也不起作用。任何关于发生了什么、为什么它不工作以及可以做些什么来使它工作的解释将不胜感激。

我试图设置一个 Thread.CurrentPrincipal 但这没有用(也许我做错了 - 你可以在代码中设置“任何东西”吗?)。如果有帮助的话,身份验证会在 httpmodule 中处理。

4

3 回答 3

8

我意识到这个问题是关于在 webapi 端点从 RestSharp 发出“真实”请求,所以这个建议并不立即适用于 OPs 场景。但是:

我正在使用HttpConfiguration,HttpServer和使用内存中的 Web Api 测试HttpMessageInvoker(很像我相信的巴德里的建议)。通过这种方式,我不需要打开侦听器或端口,因为我可以在内存中测试完整的堆栈(端到端测试)——在构建服务器、Heroku 实例等上非常方便。

使用内存测试,您可以通过以下方式设置Thread.CurrentPrincipal.. 我的测试基类有一个助手,如下所示:

protected void AuthentateRequest()
{
    Thread.CurrentPrincipal = new AuthenticatedPrincipal(Thread.CurrentPrincipal);
}

哪个使用这个:

public class AuthenticatedPrincipal : IPrincipal
{
    private readonly IPrincipal _principalToWrap;
    private readonly IIdentity _identityToWrap;

    public AuthenticatedPrincipal(IPrincipal principalToWrap)
    {
        _principalToWrap = principalToWrap;
        _identityToWrap = new AuthenticatedIdentity(principalToWrap.Identity);
    }

    public bool IsInRole(string role)
    { return _principalToWrap.IsInRole(role); }

    public IIdentity Identity
    {
        get { return _identityToWrap; }
        private set { throw new NotSupportedException(); }
    }
}

public class AuthenticatedIdentity : IIdentity
{
    private readonly IIdentity _identityToWrap;

    public AuthenticatedIdentity(IIdentity identityToWrap)
    {
        _identityToWrap = identityToWrap;
    }

    public string Name
    {
        get { return _identityToWrap.Name; }
        private set { throw new NotSupportedException(); }
    }
    public string AuthenticationType
    {
        get { return _identityToWrap.AuthenticationType; }
        private set { throw new NotSupportedException(); }
    }
    public bool IsAuthenticated
    {
        get { return true; }
        private set { throw new NotSupportedException(); }
    }
}

手动存根似乎有点过头了,IPrincipal但我尝试使用我的模拟框架,但它在我的一些测试运行程序(Resharper 和 TeamCity,但不是 NCrunch - 我认为关于在 AppDomains 上序列化的一些东西)中爆炸了。

这将设置Thread.CurrentPrincipalApiControlleraction 方法中,因此欺骗AuthorizeAttribute您相信您已通过身份验证。

于 2014-12-03T02:26:11.480 回答
5

这是您应该如何设置Thread.CurrentPrincipal. 将这样的消息处理程序添加到您的 Web API 项目中,并以如下Register方法添加处理程序WebApiConfig.csconfig.MessageHandlers.Add(new MyTestHandler());

public class MyTestHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
                                 HttpRequestMessage request,
                                     CancellationToken cancellationToken)
    {
        var local = request.Properties["MS_IsLocal"] as Lazy<bool>;
        bool isLocal = local != null && local.Value;

        if (isLocal)
        {
            if (request.Headers.GetValues("X-Testing").First().Equals("true"))
            {
                var dummyPrincipal = new GenericPrincipal(
                                        new GenericIdentity("dummy", "dummy"),
                                          new[] { "myrole1" });

                Thread.CurrentPrincipal = dummyPrincipal;

                if (HttpContext.Current != null)
                    HttpContext.Current.User = dummyPrincipal;
            }
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

这个处理程序设置了一个经过身份验证的主体,让您[Authorize]开心。这种方法存在风险因素。仅用于测试,您应该将此处理程序插入 Web API 管道。如果您将此处理程序插入生产代码中的管道(有意或无意),它基本上会破坏您的身份验证机制。为了在一定程度上降低风险(希望 API 不在本地访问),我检查以确保访问是本地的,并且有X-Testing一个值为true.

在 RestSharp 中,添加自定义标头。

var request = new RestRequest(...);
request.AddHeader("X-Testing", "true");

顺便说一句,对于集成测试,我更愿意使用内存托管,而不是网络托管。这样,Web API 在同一个测试项目中运行,你可以用它做任何你想做的事情,而不必担心在生产中破坏某些东西。有关内存托管的更多信息,请参阅thisthis

于 2013-08-05T03:52:50.467 回答
-1

为您设置身份验证器RestClient

RestClient.Authenticator = new HttpBasicAuthenticator(username, password);

使用您的自定义登录系统实际接受的身份验证器...基本、NTLM、OAuth、简单...

它在http://restsharp.org/示例的第二行中有所记录

于 2013-08-04T22:33:32.383 回答