diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs index a75ee7058..925f50c4f 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs @@ -6,7 +6,6 @@ public const string MockTag = "Mock"; public const string DefaultEndpoint = "http://13.88.8.119"; - private string _baseEndpoint; private static readonly GlobalSetting _instance = new GlobalSetting(); @@ -31,6 +30,10 @@ } } + public string ClientId { get { return "xamarin"; }} + + public string ClientSecret { get { return "secret"; }} + public string AuthToken { get; set; } public string RegisterWebsite { get; set; } @@ -45,6 +48,8 @@ public string UserInfoEndpoint { get; set; } + public string TokenEndpoint { get; set; } + public string LogoutEndpoint { get; set; } public string IdentityCallback { get; set; } @@ -59,6 +64,7 @@ BasketEndpoint = string.Format("{0}:5103", baseEndpoint); IdentityEndpoint = string.Format("{0}:5105/connect/authorize", baseEndpoint); UserInfoEndpoint = string.Format("{0}:5105/connect/userinfo", baseEndpoint); + TokenEndpoint = string.Format("{0}:5105/connect/token", baseEndpoint); LogoutEndpoint = string.Format("{0}:5105/connect/endsession", baseEndpoint); IdentityCallback = string.Format("{0}:5105/xamarincallback", baseEndpoint); LogoutCallback = string.Format("{0}:5105/Account/Redirecting", baseEndpoint); diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Token/UserToken.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Token/UserToken.cs new file mode 100644 index 000000000..1e7d2f561 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Token/UserToken.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace eShopOnContainers.Core.Models.Token +{ + public class UserToken + { + [JsonProperty("id_token")] + public string IdToken { get; set; } + + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + + [JsonProperty("refresh_token")] + public string RefreshToken { get; set; } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs index e144eb6ff..1c20db5f3 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs @@ -13,11 +13,10 @@ namespace eShopOnContainers.Core.Services.Identity // Dictionary with values for the authorize request var dic = new Dictionary(); - dic.Add("client_id", "xamarin"); - dic.Add("client_secret", "secret"); - dic.Add("response_type", "code id_token token"); + dic.Add("client_id", GlobalSetting.Instance.ClientId); + dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); + dic.Add("response_type", "code id_token"); dic.Add("scope", "openid profile basket orders offline_access"); - dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback); dic.Add("nonce", Guid.NewGuid().ToString("N")); @@ -31,7 +30,7 @@ namespace eShopOnContainers.Core.Services.Identity public string CreateLogoutRequest(string token) { - if(string.IsNullOrEmpty(token)) + if (string.IsNullOrEmpty(token)) { return string.Empty; } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/IRequestProvider.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/IRequestProvider.cs index 67b8f8c59..ba7cf8889 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/IRequestProvider.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/IRequestProvider.cs @@ -8,6 +8,8 @@ namespace eShopOnContainers.Core.Services.RequestProvider Task PostAsync(string uri, TResult data, string token = "", string header = ""); + Task PostAsync(string uri, string data, string clientId, string clientSecret); + Task DeleteAsync(string uri, string token = ""); } } \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/RequestProvider.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/RequestProvider.cs index f498532ca..e7ae41698 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/RequestProvider.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/RequestProvider.cs @@ -61,6 +61,28 @@ namespace eShopOnContainers.Core.Services.RequestProvider return result; } + public async Task PostAsync(string uri, string data, string clientId, string clientSecret) + { + HttpClient httpClient = CreateHttpClient(string.Empty); + + if (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret)) + { + AddBasicAuthenticationHeader(httpClient, clientId, clientSecret); + } + + var content = new StringContent(data); + content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); + HttpResponseMessage response = await httpClient.PostAsync(uri, content); + + await HandleResponse(response); + string serialized = await response.Content.ReadAsStringAsync(); + + TResult result = await Task.Run(() => + JsonConvert.DeserializeObject(serialized, _serializerSettings)); + + return result; + } + public async Task DeleteAsync(string uri, string token = "") { HttpClient httpClient = CreateHttpClient(token); @@ -90,6 +112,17 @@ namespace eShopOnContainers.Core.Services.RequestProvider httpClient.DefaultRequestHeaders.Add(parameter, Guid.NewGuid().ToString()); } + private void AddBasicAuthenticationHeader(HttpClient httpClient, string clientId, string clientSecret) + { + if (httpClient == null) + return; + + if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(clientSecret)) + return; + + httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(clientId, clientSecret); + } + private async Task HandleResponse(HttpResponseMessage response) { if (!response.IsSuccessStatusCode) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/ITokenService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/ITokenService.cs new file mode 100644 index 000000000..4a7bb3a06 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/ITokenService.cs @@ -0,0 +1,10 @@ +using eShopOnContainers.Core.Models.Token; +using System.Threading.Tasks; + +namespace eShopOnContainers.Core.Services.Token +{ + public interface ITokenService + { + Task GetTokenAsync(string code); + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/TokenService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/TokenService.cs new file mode 100644 index 000000000..1b6bdddf9 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Token/TokenService.cs @@ -0,0 +1,24 @@ +using System.Net; +using System.Threading.Tasks; +using eShopOnContainers.Core.Services.RequestProvider; +using eShopOnContainers.Core.Models.Token; + +namespace eShopOnContainers.Core.Services.Token +{ + public class TokenService : ITokenService + { + private readonly IRequestProvider _requestProvider; + + public TokenService(IRequestProvider requestProvider) + { + _requestProvider = requestProvider; + } + + public async Task GetTokenAsync(string code) + { + string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}", code, WebUtility.UrlEncode(GlobalSetting.Instance.IdentityCallback)); + var token = await _requestProvider.PostAsync(GlobalSetting.Instance.TokenEndpoint, data, GlobalSetting.Instance.ClientId, GlobalSetting.Instance.ClientSecret); + return token; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs index 90abb8f09..0f55ece7d 100755 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs @@ -8,6 +8,7 @@ using eShopOnContainers.Core.Services.OpenUrl; using eShopOnContainers.Core.Services.RequestProvider; using eShopOnContainers.Core.Services.Basket; using eShopOnContainers.Core.Services.Identity; +using eShopOnContainers.Core.Services.Token; using eShopOnContainers.Core.Services.Order; using eShopOnContainers.Core.Services.User; using Xamarin.Forms; @@ -52,6 +53,7 @@ namespace eShopOnContainers.Core.ViewModels.Base builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterType().As(); if (useMockServices) diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs index c174e36c8..70b3b2a5c 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs @@ -1,6 +1,7 @@ using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.Models.User; using eShopOnContainers.Core.Services.Identity; +using eShopOnContainers.Core.Services.Token; using eShopOnContainers.Core.Services.OpenUrl; using eShopOnContainers.Core.Validations; using eShopOnContainers.Core.ViewModels.Base; @@ -24,13 +25,16 @@ namespace eShopOnContainers.Core.ViewModels private IOpenUrlService _openUrlService; private IIdentityService _identityService; + private ITokenService _tokenService; public LoginViewModel( IOpenUrlService openUrlService, - IIdentityService identityService) + IIdentityService identityService, + ITokenService tokenService) { _openUrlService = openUrlService; _identityService = identityService; + _tokenService = tokenService; _userName = new ValidatableObject(); _password = new ValidatableObject(); @@ -233,10 +237,12 @@ namespace eShopOnContainers.Core.ViewModels else if (unescapedUrl.Contains(GlobalSetting.Instance.IdentityCallback)) { var authResponse = new AuthorizeResponse(url); - - if (!string.IsNullOrWhiteSpace(authResponse.AccessToken)) + if (!string.IsNullOrWhiteSpace(authResponse.Code)) { - if (authResponse.AccessToken != null) + var userToken = await _tokenService.GetTokenAsync(authResponse.Code); + string accessToken = userToken.AccessToken; + + if (!string.IsNullOrWhiteSpace(accessToken)) { Settings.AuthAccessToken = authResponse.AccessToken; Settings.AuthIdToken = authResponse.IdentityToken; diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj index d0dd19a46..fe14c795f 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj @@ -166,6 +166,9 @@ + + + @@ -259,6 +262,10 @@ MSBuild:UpdateDesignTimeXaml + + + +