所以我发现在[授权]标签上有一些点点滴滴,但没有解决我的问题。
我的场景是我有Web Api方法,我希望使用RestSharp进行集成测试。但是,RestSharp正在获取我的登录页面,而不是调用的结果。
[Authorize]
public Item GetItem([FromBody] int id)
{
return service.GetItem(id);
}
该产品使用自定义登录系统,我真正想要的是仅为集成测试禁用[授权]徽章的方法。但是我读到你可以允许匿名用户,它会“禁用”徽章,所以在解决方案中,我有一个集成测试项目,在那个项目中我有一个App.config文件。在那个文件中,我把:
<location>
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
但这似乎也没有用。任何有关正在发生的事情的解释,为什么它不起作用以及如何使这项工作都将受到高度赞赏。
我试图设置一个Thread.CurrentPrincipal但是没有用(也许我做错了 - 你能在代码中设置“任何”授权吗?)。如果有帮助,则在httpmodule中处理身份验证。
答案 0 :(得分:8)
我意识到这个问题是关于解雇&#39;真实的&#39; Restapharp在webapi端点上的请求,因此该建议不会立即适用于OP场景。但是:
我使用HttpConfiguration
,HttpServer
和HttpMessageInvoker
使用内存中的Web Api测试(很像Badri's suggestion我相信)。通过这种方式,我不需要监听器或端口打开,因为我可以在内存中测试完整堆栈(端到端测试) - 在构建服务器,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
可能看起来有点过分但我尝试使用我的mocking framework并且它在我的一些测试跑步者(Resharper和TeamCity,但不是NCrunch)中爆炸 - 有关序列化的事情我认为是AppDomains。
这会在Thread.CurrentPrincipal
操作方法中设置ApiController
,因此会误导AuthorizeAttribute
相信您已通过身份验证。
答案 1 :(得分: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);
}
}
此处理程序设置经过身份验证的主体,以使您的所有[Authorize]
满意。这种方法存在风险因素。仅用于测试,您应该将此处理程序插入Web API管道。如果将此处理程序插入生产代码中的管道(有意或无意),它基本上会破坏您的身份验证机制。为了在某种程度上降低风险(希望API不在本地访问),我检查以确保访问是本地的,并且标题X-Testing
的值为true
。
从RestSharp中,添加自定义标题。
var request = new RestRequest(...);
request.AddHeader("X-Testing", "true");
BTW,对于集成测试,我宁愿使用内存托管,而不是网络托管。这样,Web API就可以在同一个测试项目中运行,您可以随心所欲地使用它,而不必担心会破坏生产中的某些内容。有关内存中托管的详细信息,请参阅this和this。
答案 2 :(得分:-1)
为RestClient
设置身份验证器:
RestClient.Authenticator = new HttpBasicAuthenticator(username, password);
使用自定义登录系统实际接受的身份验证器... Basic,NTLM,OAuth,Simple ...
的示例的第二行中记录了这种情况