使用[授权]集成测试Web Api

Bar*_*cer 5 c# integration-testing web-config authorize-attribute asp.net-web-api

所以我发现在[Authorize]标签上有些东西让我有所启发,但没有什么可以解决我的问题.

我的场景是我有Web Api方法,我希望使用RestSharp进行集成测试.但是RestSharp正在获取我的登录页面,而不是调用的结果.

[Authorize]
public Item GetItem([FromBody] int id) 
{
   return service.GetItem(id);
}
Run Code Online (Sandbox Code Playgroud)

该产品使用自定义登录系统,我真正想要的是一种只为集成测试禁用[授权]徽章的方法.但是我读到你可以允许匿名用户,它会"禁用"徽章,所以在解决方案中,我有一个集成测试项目,在那个项目中我有一个App.config文件.在那个文件中,我把:

 <location>
  <system.web>
   <authorization>
     <allow users="?"/>
    </authorization>
  </system.web>
 </location>
Run Code Online (Sandbox Code Playgroud)

但这似乎也不起作用.任何有关正在发生的事情的解释,为什么它不起作用以及如何才能使这项工作将不胜感激.

我试图设置一个Thread.CurrentPrincipal,但是没有用(也许我做错了 - 你能在代码中设置"任何东西"吗?).如果有帮助,则在httpmodule中处理身份验证.

Mat*_*caj 8

我意识到这个问题是关于在webapi端点触发RestSharp的"真实"请求,所以这个建议不能立即适用于OP场景.但是:

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

使用内存中的测试,这里是你如何设置Thread.CurrentPrincipal..我有一个帮助我的测试基类,如下所示:

protected void AuthentateRequest()
{
    Thread.CurrentPrincipal = new AuthenticatedPrincipal(Thread.CurrentPrincipal);
}
Run Code Online (Sandbox Code Playgroud)

哪个使用这个:

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(); }
    }
}
Run Code Online (Sandbox Code Playgroud)

IPrincipal手动存根可能看起来有点过分,但是我尝试使用我的模拟框架,它在我的一些测试运行器(Resharper和TeamCity,但不是NCrunch - 我认为在AppDomains上进行序列化的事情)中爆炸了.

这将设置Thread.CurrentPrincipalApiControlleraction方法内部,因此愚弄AuthorizeAttribute相信你是经过身份验证的.


Bad*_*dri 5

这是你应该如何设置的Thread.CurrentPrincipal.将这样的消息处理程序添加到Web API项目中,并在类似的Register方法中添加处理程序WebApiConfig.cs:config.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

从RestSharp中,添加自定义标头.

var request = new RestRequest(...);
request.AddHeader("X-Testing", "true");
Run Code Online (Sandbox Code Playgroud)

顺便说一下,对于集成测试,我宁愿使用内存托管,而不是网络托管.这样,Web API就可以在同一个测试项目中运行,您可以随心所欲地使用它,而不必担心会破坏生产中的某些内容.有关内存的主机的详细信息,请参阅这个.