Skip to content

Commit a93cf01

Browse files
David BritchDavid Britch
authored andcommitted
Updated Xamarin client to use the hybrid authentication flow.
1 parent 01ede64 commit a93cf01

10 files changed

Lines changed: 121 additions & 10 deletions

File tree

src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ public class GlobalSetting
66
public const string MockTag = "Mock";
77
public const string DefaultEndpoint = "http://13.88.8.119";
88

9-
109
private string _baseEndpoint;
1110
private static readonly GlobalSetting _instance = new GlobalSetting();
1211

@@ -31,6 +30,10 @@ public string BaseEndpoint
3130
}
3231
}
3332

33+
public string ClientId { get { return "xamarin"; }}
34+
35+
public string ClientSecret { get { return "secret"; }}
36+
3437
public string AuthToken { get; set; }
3538

3639
public string RegisterWebsite { get; set; }
@@ -45,6 +48,8 @@ public string BaseEndpoint
4548

4649
public string UserInfoEndpoint { get; set; }
4750

51+
public string TokenEndpoint { get; set; }
52+
4853
public string LogoutEndpoint { get; set; }
4954

5055
public string IdentityCallback { get; set; }
@@ -59,6 +64,7 @@ private void UpdateEndpoint(string baseEndpoint)
5964
BasketEndpoint = string.Format("{0}:5103", baseEndpoint);
6065
IdentityEndpoint = string.Format("{0}:5105/connect/authorize", baseEndpoint);
6166
UserInfoEndpoint = string.Format("{0}:5105/connect/userinfo", baseEndpoint);
67+
TokenEndpoint = string.Format("{0}:5105/connect/token", baseEndpoint);
6268
LogoutEndpoint = string.Format("{0}:5105/connect/endsession", baseEndpoint);
6369
IdentityCallback = string.Format("{0}:5105/xamarincallback", baseEndpoint);
6470
LogoutCallback = string.Format("{0}:5105/Account/Redirecting", baseEndpoint);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Newtonsoft.Json;
2+
3+
namespace eShopOnContainers.Core.Models.Token
4+
{
5+
public class UserToken
6+
{
7+
[JsonProperty("id_token")]
8+
public string IdToken { get; set; }
9+
10+
[JsonProperty("access_token")]
11+
public string AccessToken { get; set; }
12+
13+
[JsonProperty("expires_in")]
14+
public int ExpiresIn { get; set; }
15+
16+
[JsonProperty("token_type")]
17+
public string TokenType { get; set; }
18+
19+
[JsonProperty("refresh_token")]
20+
public string RefreshToken { get; set; }
21+
}
22+
}

src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ public string CreateAuthorizationRequest()
1313

1414
// Dictionary with values for the authorize request
1515
var dic = new Dictionary<string, string>();
16-
dic.Add("client_id", "xamarin");
17-
dic.Add("client_secret", "secret");
18-
dic.Add("response_type", "code id_token token");
16+
dic.Add("client_id", GlobalSetting.Instance.ClientId);
17+
dic.Add("client_secret", GlobalSetting.Instance.ClientSecret);
18+
dic.Add("response_type", "code id_token");
1919
dic.Add("scope", "openid profile basket orders offline_access");
20-
2120
dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback);
2221
dic.Add("nonce", Guid.NewGuid().ToString("N"));
2322

@@ -31,7 +30,7 @@ public string CreateAuthorizationRequest()
3130

3231
public string CreateLogoutRequest(string token)
3332
{
34-
if(string.IsNullOrEmpty(token))
33+
if (string.IsNullOrEmpty(token))
3534
{
3635
return string.Empty;
3736
}

src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/IRequestProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public interface IRequestProvider
88

99
Task<TResult> PostAsync<TResult>(string uri, TResult data, string token = "", string header = "");
1010

11+
Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret);
12+
1113
Task DeleteAsync(string uri, string token = "");
1214
}
1315
}

src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/RequestProvider/RequestProvider.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,28 @@ public async Task<TResult> PostAsync<TResult>(string uri, TResult data, string t
6161
return result;
6262
}
6363

64+
public async Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret)
65+
{
66+
HttpClient httpClient = CreateHttpClient(string.Empty);
67+
68+
if (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret))
69+
{
70+
AddBasicAuthenticationHeader(httpClient, clientId, clientSecret);
71+
}
72+
73+
var content = new StringContent(data);
74+
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
75+
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
76+
77+
await HandleResponse(response);
78+
string serialized = await response.Content.ReadAsStringAsync();
79+
80+
TResult result = await Task.Run(() =>
81+
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
82+
83+
return result;
84+
}
85+
6486
public async Task DeleteAsync(string uri, string token = "")
6587
{
6688
HttpClient httpClient = CreateHttpClient(token);
@@ -90,6 +112,17 @@ private void AddHeaderParameter(HttpClient httpClient, string parameter)
90112
httpClient.DefaultRequestHeaders.Add(parameter, Guid.NewGuid().ToString());
91113
}
92114

115+
private void AddBasicAuthenticationHeader(HttpClient httpClient, string clientId, string clientSecret)
116+
{
117+
if (httpClient == null)
118+
return;
119+
120+
if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(clientSecret))
121+
return;
122+
123+
httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(clientId, clientSecret);
124+
}
125+
93126
private async Task HandleResponse(HttpResponseMessage response)
94127
{
95128
if (!response.IsSuccessStatusCode)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using eShopOnContainers.Core.Models.Token;
2+
using System.Threading.Tasks;
3+
4+
namespace eShopOnContainers.Core.Services.Token
5+
{
6+
public interface ITokenService
7+
{
8+
Task<UserToken> GetTokenAsync(string code);
9+
}
10+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Net;
2+
using System.Threading.Tasks;
3+
using eShopOnContainers.Core.Services.RequestProvider;
4+
using eShopOnContainers.Core.Models.Token;
5+
6+
namespace eShopOnContainers.Core.Services.Token
7+
{
8+
public class TokenService : ITokenService
9+
{
10+
private readonly IRequestProvider _requestProvider;
11+
12+
public TokenService(IRequestProvider requestProvider)
13+
{
14+
_requestProvider = requestProvider;
15+
}
16+
17+
public async Task<UserToken> GetTokenAsync(string code)
18+
{
19+
string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}", code, WebUtility.UrlEncode(GlobalSetting.Instance.IdentityCallback));
20+
var token = await _requestProvider.PostAsync<UserToken>(GlobalSetting.Instance.TokenEndpoint, data, GlobalSetting.Instance.ClientId, GlobalSetting.Instance.ClientSecret);
21+
return token;
22+
}
23+
}
24+
}

src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using eShopOnContainers.Core.Services.RequestProvider;
99
using eShopOnContainers.Core.Services.Basket;
1010
using eShopOnContainers.Core.Services.Identity;
11+
using eShopOnContainers.Core.Services.Token;
1112
using eShopOnContainers.Core.Services.Order;
1213
using eShopOnContainers.Core.Services.User;
1314
using Xamarin.Forms;
@@ -52,6 +53,7 @@ public static void RegisterDependencies(bool useMockServices)
5253
builder.RegisterType<DialogService>().As<IDialogService>();
5354
builder.RegisterType<OpenUrlService>().As<IOpenUrlService>();
5455
builder.RegisterType<IdentityService>().As<IIdentityService>();
56+
builder.RegisterType<TokenService>().As<ITokenService>();
5557
builder.RegisterType<RequestProvider>().As<IRequestProvider>();
5658

5759
if (useMockServices)

src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using eShopOnContainers.Core.Helpers;
22
using eShopOnContainers.Core.Models.User;
33
using eShopOnContainers.Core.Services.Identity;
4+
using eShopOnContainers.Core.Services.Token;
45
using eShopOnContainers.Core.Services.OpenUrl;
56
using eShopOnContainers.Core.Validations;
67
using eShopOnContainers.Core.ViewModels.Base;
@@ -24,13 +25,16 @@ public class LoginViewModel : ViewModelBase
2425

2526
private IOpenUrlService _openUrlService;
2627
private IIdentityService _identityService;
28+
private ITokenService _tokenService;
2729

2830
public LoginViewModel(
2931
IOpenUrlService openUrlService,
30-
IIdentityService identityService)
32+
IIdentityService identityService,
33+
ITokenService tokenService)
3134
{
3235
_openUrlService = openUrlService;
3336
_identityService = identityService;
37+
_tokenService = tokenService;
3438

3539
_userName = new ValidatableObject<string>();
3640
_password = new ValidatableObject<string>();
@@ -233,10 +237,12 @@ private async Task NavigateAsync(string url)
233237
else if (unescapedUrl.Contains(GlobalSetting.Instance.IdentityCallback))
234238
{
235239
var authResponse = new AuthorizeResponse(url);
236-
237-
if (!string.IsNullOrWhiteSpace(authResponse.AccessToken))
240+
if (!string.IsNullOrWhiteSpace(authResponse.Code))
238241
{
239-
if (authResponse.AccessToken != null)
242+
var userToken = await _tokenService.GetTokenAsync(authResponse.Code);
243+
string accessToken = userToken.AccessToken;
244+
245+
if (!string.IsNullOrWhiteSpace(accessToken))
240246
{
241247
Settings.AuthAccessToken = authResponse.AccessToken;
242248
Settings.AuthIdToken = authResponse.IdentityToken;

src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@
166166
<Compile Include="Converters\FirstValidationErrorConverter.cs" />
167167
<Compile Include="Effects\EntryLineColorEffect.cs" />
168168
<Compile Include="Behaviors\LineColorBehavior.cs" />
169+
<Compile Include="Models\Token\UserToken.cs" />
170+
<Compile Include="Services\Token\TokenService.cs" />
171+
<Compile Include="Services\Token\ITokenService.cs" />
169172
</ItemGroup>
170173
<ItemGroup>
171174
<None Include="app.config" />
@@ -259,6 +262,10 @@
259262
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
260263
</EmbeddedResource>
261264
</ItemGroup>
265+
<ItemGroup>
266+
<Folder Include="Models\Token\" />
267+
<Folder Include="Services\Token\" />
268+
</ItemGroup>
262269
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
263270
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
264271
<PropertyGroup>

0 commit comments

Comments
 (0)