Hi,
We need to create a desktop client (WPF) and we would like to utilise the dynamic HTTP proxies however I can't seem to find a service / proxy that will allow a user login. A login method doesn't seem to exist on the IAcoountAppService. Does a login method exist elsewhere? Am I missing something?
I can obviously login via a HttpClient however I can't see how to do this while using the dynamic proxies (the proxies will use a separate client that hasn't been logged in).
Appreciate any help.
Thanks
Ian
4 Answer(s)
-
0
hi,
you can use OpenID Connect. See our demo application (Angular client), https://commercial.abp.io/demo it calls
http://9cc87abb646dbc56.demo.commercial.abp.io/.well-known/openid-configuration
then makes a request tohttp://9cc87abb646dbc56.demo.commercial.abp.io/connect/token
See also https://docs.abp.io/en/abp/latest/Samples/Microservice-Demo#authentication
-
0
Hi,
Thanks for the above. I'm still strugglling to piece together how openid connect can be utilised with the dynamic http proxies. Do you have a c# sample?
i've looked at the sample console client in inhttps://github.com/abpframework/abp/blob/dev/samples/MicroserviceDemo/applications/ConsoleClientDemo/ClientDemoService.cs.
However, this seems to use a different authenication process. Can you please explain how OpenID connect can be used to login such that subsequent calls using the dynamic proxies to not fail (user not logged in). Do I need to update the underlaying HTTP client headers with the token recieved from OpenID connect?
I suspect I'm missing something simple or my understanding of the authentication process is flawed.
Any help greatly appreciated.
Thanks
Isn
-
1
Hi,
We are using the Identity Server for authentication. There are some different flows, but I think the most convinient way is to use the resource owner password flow for your case.
The downloaded startup template has a .HttpApi.Client.ConsoleTestApp project which authenticates using this flow by default. However, it assumes that username and password is hard-coded in the appsettings.json. I will explain you how to convert this project to dynamically get username & password from user, then authenticate and get access token.
- Create an
AccessTokenManager
class like that:
using System; using System.Net.Http; using System.Threading.Tasks; using IdentityModel.Client; using Volo.Abp.DependencyInjection; namespace MyCompanyName.MyProjectName.HttpApi.Client.ConsoleTestApp { public class AccessTokenManager : ISingletonDependency { public string AccessToken { get; private set; } private readonly IHttpClientFactory _httpClientFactory; public AccessTokenManager(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task ObtainAccessToken() { Console.Write("Username: "); var userName = Console.ReadLine(); Console.Write("Password: "); var password = Console.ReadLine(); var discoveryResponse = await GetDiscoveryResponse(); var tokenResponse = await GetTokenResponse(discoveryResponse, userName, password); AccessToken = tokenResponse.AccessToken; } protected async Task<DiscoveryDocumentResponse> GetDiscoveryResponse() { using (var httpClient = _httpClientFactory.CreateClient()) { return await httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest { Address = "https://localhost:44301", Policy = { RequireHttps = true } }); } } protected async Task<TokenResponse> GetTokenResponse( DiscoveryDocumentResponse discoveryResponse, string userName, string password ) { using (var httpClient = _httpClientFactory.CreateClient()) { return await httpClient.RequestPasswordTokenAsync( await CreatePasswordTokenRequestAsync(discoveryResponse, userName, password) ); } } protected virtual Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync( DiscoveryDocumentResponse discoveryResponse, string userName, string password) { var request = new PasswordTokenRequest { Address = discoveryResponse.TokenEndpoint, Scope = "MyProjectName", ClientId = "MyProjectName_App", ClientSecret = "1q2w3e*", UserName = userName, Password = password }; return Task.FromResult(request); } } }
ObtainAccessToken()
method gets user & pass from console, authenticates to the identity server (just as described in the IDS4 documentation), then sets it to theAccessToken
property. This class is singleton, so you can access the token from another service later.I've written the configuration hard-coded, you need to refactor the code :)
- ABP Framework's dynamic c# proxy system uses the
IRemoteServiceHttpClientAuthenticator
to get the access token. So, you need to implement it:
using System.Threading.Tasks; using IdentityModel.Client; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.Authentication; namespace MyCompanyName.MyProjectName.HttpApi.Client.ConsoleTestApp { public class MyRemoteServiceHttpClientAuthenticator : IRemoteServiceHttpClientAuthenticator, ITransientDependency { private readonly AccessTokenManager _accessTokenManager; public MyRemoteServiceHttpClientAuthenticator(AccessTokenManager accessTokenManager) { _accessTokenManager = accessTokenManager; } public Task Authenticate(RemoteServiceHttpClientAuthenticateContext context) { context.Client.SetBearerToken(_accessTokenManager.AccessToken); return Task.CompletedTask; } } }
This gets the token from the
AccessTokenManager
. It is very simple.- Call the
AccessTokenManager.ObtainAccessToken()
on your login screen of the WPF app. In this console app, I called it inside theConsoleTestAppHostedService
, before theClientDemoService
usage:
await application.ServiceProvider .GetRequiredService<AccessTokenManager>() .ObtainAccessToken(); var demo = application.ServiceProvider.GetRequiredService<ClientDemoService>(); await demo.RunAsync();
That's all! Enjoy with the ABP Framework :)
- Create an
-
0
Thanks for the excellent response. Much appreciated.