如何让我的 ServiceStack 测试使用 RestSharp 进行身份验证

本文关键字:RestSharp 身份验证 测试 我的 ServiceStack | 更新日期: 2023-09-27 18:34:30

我在我的ServiceStack应用程序中实现了CustomCredentialsAuth的工作实现。我可以使用身份验证凭据访问 URL,它按预期工作。

然而,在我的测试中,我的运气不一样。

我正在使用 RestSharp,如果我禁用 [Authenticate] ,我可以让我所有的测试通过。

启用[Authenticate]并运行测试给了我

预期:正常
但是是:未经授权

这是我的测试。如何让 RestSharp 为我的测试进行身份验证?

using System;
using System.Net;
using FutureState.AppCore.Tests.Integration.Repositories.Fixtures;
using NUnit.Framework;
using RestSharp;
namespace FutureState.AppCore.Tests.Functional.Services
{
    [TestFixture]
    public class UserServiceInterfaceTests
    {
        private RestSchemaValidator _restSchemaValidator;
        private string _testLoginEmail;
        private string _testLoginPassword;
        [SetUp]
        public void SetUp ()
        {
            _restSchemaValidator = new RestSchemaValidator();
            _testLoginEmail = UserFixture.SystemAccount.Email;
            _testLoginPassword = "password";
        }
        [Test]
        public void ShouldGetAListOfUsersAndReturnStatusOk ()
        {
                // Setup
                var client = new RestClient( ServiceTestAppHostBase.BaseUrl );
                client.Authenticator = new HttpBasicAuthenticator( _testLoginEmail, _testLoginPassword );
                var request = new RestRequest( "/users/", Method.GET ) { RequestFormat = DataFormat.Json };
                // Execute
                var response = client.Execute( request );
                // Assert
                Assert.That( response.ErrorMessage, Is.Null );
                Assert.That( response.StatusCode, Is.EqualTo( HttpStatusCode.OK ) );
                _restSchemaValidator.ValidateResponse( "ExpectedUsersResponse.json", response.Content );
        }
        [Test]
        public void ShouldGetAUserAndReturnStatusOk ()
        {
            // Setup
            var expectedUserId = new Guid( UserFixture.FirstUserId );
            var client = new RestClient( ServiceTestAppHostBase.BaseUrl );
            client.Authenticator = new HttpBasicAuthenticator( _testLoginEmail, _testLoginPassword );
            var request = new RestRequest( "/users/" + expectedUserId, Method.GET ) { RequestFormat = DataFormat.Json };
            // Execute
            var response = client.Execute( request );
            // Assert
            Assert.That( response.ErrorMessage, Is.Null );
            Assert.That( response.StatusCode, Is.EqualTo( HttpStatusCode.OK ) );
            _restSchemaValidator.ValidateResponse( "ExpectedUserResponse.json", response.Content );
        }
    }
}

我正在使用自定义身份验证提供程序:

public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
    private readonly IUserService _userService;
    private Guid _userId;
    public CustomCredentialsAuthProvider ( Container container )
    {
        _userService = container.Resolve<IUserService>();
    }
    public override bool TryAuthenticate ( IServiceBase authService, string email, string password )
    {
        var user = _userService.GetByEmailAddress( email );
        user.Password = password; // Add the posted password to the user object before authenticating.
        _userId = user.Id;
        return _userService.CheckPassword( user );
    }
    public override void OnAuthenticated ( IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo )
    {
        session.Id = _userId.ToString();
        //Important: You need to save the session!
        authService.SaveSession( session, SessionExpiry );
    }
}

我的TestAppHostBase像这样连接身份验证。

private void ConfigureAuth ( Container container )
{
    //Default route: /auth/{provider}
    Plugins.Add( new AuthFeature( () => new AuthUserSession(),
     new IAuthProvider[] {
         new CustomCredentialsAuthProvider(container)
     } ) );
    //Default route: /register
    Plugins.Add( new RegistrationFeature() );
}

进一步开发,调用以下代码确实为用户返回 true,但显然不会将会话数据传递给后续RestRequest

// Calling this returns TRUE for TryAuthenticate
// But doesn't retain the session data for the subsequenet request.
var container = EndpointHost.AppHost.TryResolve<Container>();
var authService = new AuthService();
var customCredentialsAuthProvider = new CustomCredentialsAuthProvider( container );
customCredentialsAuthProvider.TryAuthenticate(authService, _testLoginEmail, _testLoginPassword);

如何让我的 ServiceStack 测试使用 RestSharp 进行身份验证

因此,事实证明,我们可以想出解决此问题的最佳方法是使用CookieContainer并将其作为客户端的一部分传递。

首先,我们为 ServiceInterfaceTests 创建了一个基类。

public class ServiceInterfaceTestBase
{
    protected  IRestClient Client;
    protected void AuthenticateClient(string email, string password)
    {
        Client = new RestClient( ServiceTestAppHostBase.BaseUrl );
        var login = new RestRequest( "/auth", Method.POST );
        login.AddParameter( "username", email );
        login.AddParameter( "password", password );
        var response = Client.Execute( login );
        var cookieJar = new CookieContainer();
        if ( response.StatusCode == HttpStatusCode.OK )
        {
            var cookie = response.Cookies.FirstOrDefault();
            cookieJar.Add( new Cookie( cookie.Name, cookie.Value, cookie.Path, cookie.Domain ) );
        }
        Client.CookieContainer = cookieJar;  
    }
}

ServiceInterfaceTests继承自它

[TestFixture]
public class UserServiceInterfaceTests : ServiceInterfaceTestBase
{

然后在我们的设置中,我们调用身份验证方法。

[SetUp]
public void SetUp ()
{
    _restSchemaValidator = new RestSchemaValidator();
    _testLoginEmail = UserFixture.SystemAccount.Email;
    _testLoginPassword = "password"; // the database contains a hashed password version of "password".
  AuthenticateClient(_testLoginEmail, _testLoginPassword);
}

最后,我们的测试看起来像

[Test]
public void ShouldGetAListOfUsersAndReturnStatusOk ()
{
    // Setup
    var request = new RestRequest( "/users/", Method.GET ) { RequestFormat = DataFormat.Json, };
    // Execute
    var response = Client.Execute( request );
    // Assert
    Assert.That( response.ErrorMessage, Is.Null );
    Assert.That( response.StatusCode, Is.EqualTo( HttpStatusCode.OK ) );
    _restSchemaValidator.ValidateResponse( "ExpectedUsersResponse.json", response.Content );
    Trace.Write( response.Content );
}