From b11cc33008827ea6972b09331bfb4c72fcb1bf9e Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Sun, 26 May 2019 15:54:15 +0300 Subject: [PATCH] Added FakeCurrentPrincipalAccessor, created an authorized test. --- .../host/ConsoleClient/ClientDemoService.cs | 146 +++++++++++++++++- .../host/ConsoleClient/appsettings.json | 6 +- .../Samples/ISampleAppService.cs | 2 + .../Samples/SampleAppService.cs | 12 ++ .../Samples/SampleController.cs | 9 ++ .../Samples/SampleAppService_Tests.cs | 7 + .../Security/FakeCurrentPrincipalAccessor.cs | 39 +++++ 7 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 templates/service/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs diff --git a/templates/service/host/ConsoleClient/ClientDemoService.cs b/templates/service/host/ConsoleClient/ClientDemoService.cs index cc37a2e7e2..969cc30d7b 100644 --- a/templates/service/host/ConsoleClient/ClientDemoService.cs +++ b/templates/service/host/ConsoleClient/ClientDemoService.cs @@ -1,22 +1,156 @@ -using System.Threading.Tasks; +using System; +using System.Net.Http; +using System.Threading.Tasks; +using IdentityModel.Client; +using MyCompanyName.MyProjectName.Samples; +using Volo.Abp.Configuration; using Volo.Abp.DependencyInjection; +using Volo.Abp.IdentityModel; namespace ConsoleClient { public class ClientDemoService : ITransientDependency { - //private readonly ISampleAppService _sampleAppService; + private readonly ISampleAppService _sampleAppService; + private readonly IIdentityModelAuthenticationService _authenticationService; + private readonly IConfigurationAccessor _configurationAccessor; public ClientDemoService( - //ISampleAppService sampleAppService - ) + ISampleAppService sampleAppService, + IIdentityModelAuthenticationService authenticationService, + IConfigurationAccessor configurationAccessor) { - //_sampleAppService = sampleAppService; + _sampleAppService = sampleAppService; + _authenticationService = authenticationService; + _configurationAccessor = configurationAccessor; } public async Task RunAsync() { - //var output = await _sampleAppService.Method1Async(); + await TestWithDynamicProxiesAsync(); + await TestWithHttpClientAndIdentityModelAuthenticationServiceAsync(); + await TestAllManuallyAsync(); + } + + /* Shows how to perform an HTTP request to the API using ABP's dynamic c# proxy + * feature. It is just simple as calling a local service method. + * Authorization and HTTP request details are handled by the ABP framework. + */ + private async Task TestWithDynamicProxiesAsync() + { + Console.WriteLine(); + Console.WriteLine($"***** {nameof(TestWithDynamicProxiesAsync)} *****"); + + var result = await _sampleAppService.GetAsync(); + Console.WriteLine("Result: " + result.Value); + + result = await _sampleAppService.GetAuthorizedAsync(); + Console.WriteLine("Result (authorized): " + result.Value); + } + + /* Shows how to use HttpClient to perform a request to the HTTP API. + * It uses ABP's IIdentityModelAuthenticationService to simplify obtaining access tokens. + */ + private async Task TestWithHttpClientAndIdentityModelAuthenticationServiceAsync() + { + Console.WriteLine(); + Console.WriteLine($"***** {nameof(TestWithHttpClientAndIdentityModelAuthenticationServiceAsync)} *****"); + + //Get access token using ABP's IIdentityModelAuthenticationService + + var accessToken = await _authenticationService.GetAccessTokenAsync( + new IdentityClientConfiguration( + _configurationAccessor.Configuration["IdentityClients:Default:Authority"], + _configurationAccessor.Configuration["IdentityClients:Default:Scope"], + _configurationAccessor.Configuration["IdentityClients:Default:ClientId"], + _configurationAccessor.Configuration["IdentityClients:Default:ClientSecret"], + _configurationAccessor.Configuration["IdentityClients:Default:GrantType"], + _configurationAccessor.Configuration["IdentityClients:Default:UserName"], + _configurationAccessor.Configuration["IdentityClients:Default:UserPassword"] + ) + ); + + //Perform the actual HTTP request + + using (var httpClient = new HttpClient()) + { + httpClient.SetBearerToken(accessToken); + + var url = _configurationAccessor.Configuration["RemoteServices:Default:BaseUrl"] + + "api/MyProjectName/sample/authorized"; + + var responseMessage = await httpClient.GetAsync(url); + if (responseMessage.IsSuccessStatusCode) + { + var responseString = await responseMessage.Content.ReadAsStringAsync(); + Console.WriteLine("Result: " + responseString); + } + else + { + throw new Exception("Remote server returns error code: " + responseMessage.StatusCode); + } + } + } + + /* Shows how to use HttpClient to perform a request to the HTTP API. + * It obtains access token using IdentityServer's API. See its documentation: + * https://identityserver4.readthedocs.io/en/latest/quickstarts/2_resource_owner_passwords.html + */ + private async Task TestAllManuallyAsync() + { + Console.WriteLine(); + Console.WriteLine($"***** {nameof(TestAllManuallyAsync)} *****"); + + //Obtain access token from the IDS4 server + + // discover endpoints from metadata + var client = new HttpClient(); + var disco = await client.GetDiscoveryDocumentAsync(_configurationAccessor.Configuration["IdentityClients:Default:Authority"]); + if (disco.IsError) + { + Console.WriteLine(disco.Error); + return; + } + + // request token + var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest + { + Address = disco.TokenEndpoint, + ClientId = _configurationAccessor.Configuration["IdentityClients:Default:ClientId"], + ClientSecret = _configurationAccessor.Configuration["IdentityClients:Default:ClientSecret"], + UserName = _configurationAccessor.Configuration["IdentityClients:Default:UserName"], + Password = _configurationAccessor.Configuration["IdentityClients:Default:UserPassword"], + Scope = _configurationAccessor.Configuration["IdentityClients:Default:Scope"] + }); + + if (tokenResponse.IsError) + { + Console.WriteLine(tokenResponse.Error); + return; + } + + Console.WriteLine(tokenResponse.Json); + + //Perform the actual HTTP request + + using (var httpClient = new HttpClient()) + { + httpClient.SetBearerToken(tokenResponse.AccessToken); + + var url = _configurationAccessor.Configuration["RemoteServices:Default:BaseUrl"] + + "api/MyProjectName/sample/authorized"; + + var responseMessage = await httpClient.GetAsync(url); + if (responseMessage.IsSuccessStatusCode) + { + var responseString = await responseMessage.Content.ReadAsStringAsync(); + Console.WriteLine("Result: " + responseString); + } + else + { + throw new Exception("Remote server returns error code: " + responseMessage.StatusCode); + } + } } } } \ No newline at end of file diff --git a/templates/service/host/ConsoleClient/appsettings.json b/templates/service/host/ConsoleClient/appsettings.json index e183f6ba53..7cbe3a2926 100644 --- a/templates/service/host/ConsoleClient/appsettings.json +++ b/templates/service/host/ConsoleClient/appsettings.json @@ -1,17 +1,17 @@ { "RemoteServices": { "Default": { - "BaseUrl": "https://localhost:44395/" + "BaseUrl": "http://localhost:57992/" } }, "IdentityClients": { "Default": { "GrantType": "password", - "ClientId": "MyProjectName_ConsoleTestApp", + "ClientId": "ConsoleClient", "ClientSecret": "1q2w3e*", "UserName": "admin", "UserPassword": "1q2w3E*", - "Authority": "https://localhost:44348", + "Authority": "http://localhost:61517", "Scope": "MyProjectName" } } diff --git a/templates/service/src/MyCompanyName.MyProjectName.Application.Contracts/Samples/ISampleAppService.cs b/templates/service/src/MyCompanyName.MyProjectName.Application.Contracts/Samples/ISampleAppService.cs index 1f5621ba8d..206e81bebe 100644 --- a/templates/service/src/MyCompanyName.MyProjectName.Application.Contracts/Samples/ISampleAppService.cs +++ b/templates/service/src/MyCompanyName.MyProjectName.Application.Contracts/Samples/ISampleAppService.cs @@ -6,5 +6,7 @@ namespace MyCompanyName.MyProjectName.Samples public interface ISampleAppService : IApplicationService { Task GetAsync(); + + Task GetAuthorizedAsync(); } } diff --git a/templates/service/src/MyCompanyName.MyProjectName.Application/Samples/SampleAppService.cs b/templates/service/src/MyCompanyName.MyProjectName.Application/Samples/SampleAppService.cs index 4534038f9e..d193c3f895 100644 --- a/templates/service/src/MyCompanyName.MyProjectName.Application/Samples/SampleAppService.cs +++ b/templates/service/src/MyCompanyName.MyProjectName.Application/Samples/SampleAppService.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; namespace MyCompanyName.MyProjectName.Samples { @@ -13,5 +14,16 @@ namespace MyCompanyName.MyProjectName.Samples } ); } + + [Authorize] + public Task GetAuthorizedAsync() + { + return Task.FromResult( + new SampleDto + { + Value = 42 + } + ); + } } } \ No newline at end of file diff --git a/templates/service/src/MyCompanyName.MyProjectName.HttpApi/Samples/SampleController.cs b/templates/service/src/MyCompanyName.MyProjectName.HttpApi/Samples/SampleController.cs index 8e67cd463d..7c4de3b65e 100644 --- a/templates/service/src/MyCompanyName.MyProjectName.HttpApi/Samples/SampleController.cs +++ b/templates/service/src/MyCompanyName.MyProjectName.HttpApi/Samples/SampleController.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; @@ -20,5 +21,13 @@ namespace MyCompanyName.MyProjectName.Samples { return await _sampleAppService.GetAsync(); } + + [HttpGet] + [Route("authorized")] + [Authorize] + public async Task GetAuthorizedAsync() + { + return await _sampleAppService.GetAsync(); + } } } diff --git a/templates/service/test/MyCompanyName.MyProjectName.Application.Tests/Samples/SampleAppService_Tests.cs b/templates/service/test/MyCompanyName.MyProjectName.Application.Tests/Samples/SampleAppService_Tests.cs index 6d1e4ae549..183f8d0063 100644 --- a/templates/service/test/MyCompanyName.MyProjectName.Application.Tests/Samples/SampleAppService_Tests.cs +++ b/templates/service/test/MyCompanyName.MyProjectName.Application.Tests/Samples/SampleAppService_Tests.cs @@ -19,5 +19,12 @@ namespace MyCompanyName.MyProjectName.Samples var result = await _sampleAppService.GetAsync(); result.Value.ShouldBe(42); } + + [Fact] + public async Task GetAuthorizedAsync() + { + var result = await _sampleAppService.GetAuthorizedAsync(); + result.Value.ShouldBe(42); + } } } diff --git a/templates/service/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs b/templates/service/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs new file mode 100644 index 0000000000..4196dd09e1 --- /dev/null +++ b/templates/service/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; + +namespace MyCompanyName.MyProjectName.Security +{ + [Dependency(ReplaceServices = true)] + public class FakeCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency + { + public ClaimsPrincipal Principal => GetPrincipal(); + private ClaimsPrincipal _principal; + + private ClaimsPrincipal GetPrincipal() + { + if (_principal == null) + { + lock (this) + { + if (_principal == null) + { + _principal = new ClaimsPrincipal( + new ClaimsIdentity( + new List + { + new Claim(AbpClaimTypes.UserId,"2e701e62-0953-4dd3-910b-dc6cc93ccb0d"), + new Claim(AbpClaimTypes.UserName,"admin"), + new Claim(AbpClaimTypes.Email,"admin@abp.io") + } + ) + ); + } + } + } + + return _principal; + } + } +}