繁体   English   中英

使用asp.net核心中的Identity server4进行登录控制器的API集成测试

[英]API Integration Test for Login controller using Identity server4 in asp.net core

我在使用IdentityServer4测试Login Controller时遇到问题。 它会引发以下错误:

{System.Net.Http.WinHttpException(0x80072EFD):无法建立与服务器的连接

我正在尝试使用ResourceOwnerPassword生成访问令牌,我已经实现了IResourceOwnerPasswordValidator。 当我调用RequestResourcePasswordAsync时,我在UserAccessToken.cs类中收到错误。 我很确定这是因为处理程序。 因为如果我在我的测试类中使用处理程序并使用该处理程序调用TokenClient,我会获得访问令牌但是我无法测试我的登录控制器。

LoginController.cs

[HttpPost]
public async Task<IActionResult> Login([FromBody]LoginViewModel user)
{       
    var accessToken = await UserAccessToken.GenerateTokenAsync(user.Username, user.Password);
    var loginToken = JsonConvert.DeserializeObject(accessToken);
    return Ok(loginToken); 
}

UserAccessToken.cs

public async Task<string> GenerateTokenAsync(string username, string password)
        {
            var tokenUrl = "http://localhost:5000/connect/token";
            var tokenClient = new TokenClient(tokenUrl,"ClientId","ClientPassword");
            var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(username, password, SecurityConfig.PublicApiResourceId);
            if (tokenResponse.IsError)
            {
                throw new AuthenticationFailedException(tokenResponse.Error);
            }
            return tokenResponse.Json.ToString();

        }

TestClass.cs

 [Fact]
 public async Task Login()
 {          
     var client = _identityServer.CreateClient();
     var data = new StringContent(JsonConvert.SerializeObject(new LoginViewModel { Username = "1206", Password = "5m{F?Hk92/Qj}n7Lp6" }), Encoding.UTF8, "application/json");
     var dd = await client.PostAsync("http://localhost:5000/login", data);
     var ss = dd;
 }

IdentityServerSetup.cs //集成测试设置

public class IdentityServerSetup
{
    private TestServer _identityServer;
    private const string TokenEndpoint = "http://localhost:5000/connect/token";
    public HttpMessageHandler _handler;

    //IF I use this code I do get a AccessToken
    public async Task<string> GetAccessTokenForUser(string userName, string password, string clientId, string clientSecret, string apiName = "integrapay.api.public")
    {
        var client = new TokenClient(TokenEndpoint, clientId, clientSecret, innerHttpMessageHandler: _handler);
        var response = await client.RequestResourceOwnerPasswordAsync(userName, password, apiName);
        return response.AccessToken;    
    }
}

好吧,你已经自己回答了这个问题:问题在于TokenClient使用的HttpHandler 它应该使用TestServer提供的那个成功地与它进行通信,而不是对localhost进行实际请求。

现在, UserAccessToken需要TokenClient 这是您的类的依赖项,因此您应该重构代码以传递TokenClient而不是自己生成它。 这种模式称为依赖注入 ,非常适合像您这样的情况,您的测试可能与生产设置中的要求不同。

您可以使代码看起来像这样:

UserAccessToken.cs

public class UserAccessToken
{
    private readonly TokenClient _tokenClient;

    public UserAccessToken(TokenClient tokenClient)
    {
        _tokenClient = tokenClient;
    }

    public async Task<string> GenerateTokenAsync(string username, string password)
    {
        var tokenUrl = "http://localhost:5000/connect/token";
        var tokenResponse = await _tokenClient.RequestResourceOwnerPasswordAsync(username, password, SecurityConfig.PublicApiResourceId);
        if (tokenResponse.IsError)
        {
            throw new AuthenticationFailedException(tokenResponse.Error);
        }
        return tokenResponse.Json.ToString();
    }
}

TestHelpers.cs

public static class TestHelpers
{
    private static TestServer _testServer;
    private static readonly object _initializationLock = new object();

    public static TestServer GetTestServer()
    {
        if (_testServer == null)
        {
            InitializeTestServer();
        }
        return _testServer;
    }

    private static void InitializeTestServer()
    {
        lock (_initializationLock)
        {
            if (_testServer != null)
            {
                return;
            }
            var webHostBuilder = new WebHostBuilder()
                .UseStartup<IntegrationTestsStartup>();
            var testServer = new TestServer(webHostBuilder);
            var initializationTask = InitializeDatabase(testServer);
            initializationTask.ConfigureAwait(false);
            initializationTask.Wait();
            testServer.BaseAddress = new Uri("http://localhost");
            _testServer = testServer;
        }
    }
}

IntegrationTestsStartup.cs

public class IntegrationTestsStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<TokenClient>(() =>
        {
            var handler = TestUtilities.GetTestServer().CreateHandler();
            var client = new TokenClient(TokenEndpoint, clientId, clientSecret, innerHttpMessageHandler: handler);
            return client;
        };
        services.AddTransient<UserAccessToken>();
    }
}

LoginController.cs

public class LoginController : Controller
{
    private readonly UserAccessToken _userAccessToken;

    public LoginController(UserAccessToken userAccessToken)
    {
        _userAccessToken = userAccessToken;
    }

    [HttpPost]
    public async Task<IActionResult> Login([FromBody]LoginViewModel user)
    {
        var accessToken = await _userAccessToken .GenerateTokenAsync(user.Username, user.Password);
        var loginToken = JsonConvert.DeserializeObject(accessToken);
        return Ok(loginToken);
    }
}

是我一个GitHub项目 ,它使用TestServer类并显示我是如何使用它的。 但它并没有使用IdentityServer4。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM