如何使用RestSharp传递ClaimsPrincipal

时间:2015-06-30 16:20:11

标签: unit-testing asp.net-web-api restsharp claims-based-identity

我在使用RestSharp测试我的Web.API方法的特定实现方面遇到了一些麻烦。我在开放(非安全)方法中执行POSTS和GETS非常成功。但是,当我必须发送令牌以确定访问权限时,我会遇到问题。

以下是实施:

我正在为我的Web.API使用OWIN中间件。客户端必须发送到令牌服务才能获得包含其声明的给定令牌。所有这一切都运作良好。

在我的测试中,我的初始化程序具有以下代码,该代码发布到令牌服务并获取令牌。这非常有效 - 按照宣传的那样返回令牌:

 [TestInitialize]
    public void SetupTest()
    {

        _verificationErrors = new StringBuilder();

        _client = new RestClient
        {
            BaseUrl = new Uri(ConfigurationManager.AppSettings["ServicesBaseUrl"])
        };

        _serviceRequestPrepender = ConfigurationManager.AppSettings["ServiceRequestPrepender"];

        // Initialize this by getting the user token put back for all of the tests to use.
        var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, ConfigurationManager.AppSettings["TokenEndpointPath"]), Method.POST);

        // Add header stuff
        request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);
        request.AddParameter("Accept", "application/json", ParameterType.HttpHeader);

        // Add request body
        _userName = "{test student name}";
        _password = "{test student password}";
        _userGuid = "{this is a guid value!!}";

        _clientIdentifier = ConfigurationManager.AppSettings["ClientIdentifier"];
        _applicationId = ConfigurationManager.AppSettings["ApplicationId"];

        string encodedBody = string.Format("grant_type=password&username={0}&password={1}&scope={2} {3} {4} {0}"
                                           , _userName, _password, _clientIdentifier, _userGuid, _applicationId);
        request.AddParameter("application/x-www-form-urlencoded", encodedBody, ParameterType.RequestBody);


        // execute the request
        IRestResponse response = _client.Execute(request);

        // Make sure everything is working as promised.
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        Assert.IsTrue(response.ContentLength > 0);

        _token = new JavaScriptSerializer().Deserialize<Token>(response.Content).access_token;

    }

接下来是下面的代码,它调用一个Web.API方法,该方法将给定的标记传递给另一个Web.API方法,我正在执行GET以从我的服务中提取一些信息。

        [TestMethod]
    public void GetUserProfileTest()
    {

        // Arrange
        var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, "api/UserProfiles/UserProfiles/Get/{appId}/{userId}/{username}"), Method.GET);

        // Add header stuff
        request.AddParameter("Content-Type", "application/json", ParameterType.HttpHeader);
        request.AddParameter("Accept", "/application/json", ParameterType.HttpHeader);
        request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token));

        request.AddUrlSegment("appId", "1");
        request.AddUrlSegment("userId", _userGuid);
        request.AddUrlSegment("username", _userName);

        // execute the request
        IRestResponse response = _client.Execute(request);

        // Make sure everything is working as promised.
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        Assert.IsTrue(response.ContentLength > 0); // do more when working

    }

接下来,调用该服务,但我使用自定义访问安全性检查修饰了Web.API方法。这是一个非常简单的安全检查,它只检查令牌是否有效且未过期。以下是该属性的IsAuthorized方法:

        protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        // Custom Code here
        return ValidityChecker.IsTokenValid(actionContext);
    }

ValidityChecker是一个简单的类,只检查令牌是否有效:

    public class TokenValidityChecker
{
    public ClaimsPrincipal PrincipalWithClaims { get; private set; }

    /// <summary>
    /// Extracts out the ability to perform token checking since all Token checking attributes will need t his.
    /// </summary>
    /// <param name="actionContext"></param>
    /// <returns></returns>
    public bool IsTokenValid(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        bool result = false;

        var principal = actionContext.RequestContext.Principal;
        if (principal.GetType() == typeof(ClaimsPrincipal))
        {
            PrincipalWithClaims = (ClaimsPrincipal)principal;
            result = PrincipalWithClaims.Identity.IsAuthenticated;
        }

        // Custom Code here
        return result;
    }
}

所以,有了背景 - 这就是问题所在。正如您所看到的,通常,当调用服务时,ValidityChecker将收到HttpActionContext。除此之外,该HttpActionContext的RequestContext.Principal通常也是ClaimsPrincipal类型。

但是,当从单元测试运行并使用RestSharp时,它当然是WindowsPrincipal。

有没有办法使用RestSharp来制作一个ClaimsPrincipal?我已经尝试使用Authorization参数确保令牌包含在标头中,但没有任何运气。

1 个答案:

答案 0 :(得分:1)

好吧 - 如果我只是阅读我自己的代码的细节,我很久以前就可以完成这个。

答案非常简单。问题中的代码将令牌添加到参数中,但不会将其注释为HttpHeader。我忘了把它放到方法调用中。以下是修复它的行:

            request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token), ParameterType.HttpHeader);

&#34; ParameterType.HttpHeader&#34;在方法调用中做了伎俩。