Browse Source

Added initial integration with IdentityServer

pull/49/merge
Javier Suárez Ruiz 8 years ago
parent
commit
d292646f3c
12 changed files with 285 additions and 15 deletions
  1. +49
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Behaviors/WebViewNavigationBehavior.cs
  2. +5
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs
  3. +8
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IIdentityService.cs
  4. +61
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs
  5. +2
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs
  6. +78
    -3
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs
  7. +49
    -2
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/LoginView.xaml
  8. +19
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/LoginView.xaml.cs
  9. +7
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj
  10. +1
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/packages.config
  11. +1
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj
  12. +5
    -8
      src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak

+ 49
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Behaviors/WebViewNavigationBehavior.cs View File

@ -0,0 +1,49 @@
using System.Windows.Input;
using Xamarin.Forms;
namespace eShopOnContainers.Core.Behaviors
{
public class WebViewNavigationBehavior : Behavior<WebView>
{
private VisualElement _element;
public static readonly BindableProperty NavigateCommandProperty =
BindableProperty.Create("NavigateCommand", typeof(ICommand),
typeof(WebViewNavigationBehavior), default(ICommand),
BindingMode.OneWay, null);
public ICommand NavigateCommand
{
get { return (ICommand)GetValue(NavigateCommandProperty); }
set { SetValue(NavigateCommandProperty, value); }
}
protected override void OnAttachedTo(WebView bindable)
{
_element = bindable;
bindable.Navigating += OnWebViewNavigating;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(WebView bindable)
{
_element = null;
BindingContext = null;
bindable.Navigating -= OnWebViewNavigating;
bindable.BindingContextChanged -= OnBindingContextChanged;
}
private void OnBindingContextChanged(object sender, System.EventArgs e)
{
BindingContext = _element?.BindingContext;
}
private void OnWebViewNavigating(object sender, WebNavigatingEventArgs e)
{
if (NavigateCommand != null && NavigateCommand.CanExecute(e.Url))
{
NavigateCommand.Execute(e.Url);
}
}
}
}

+ 5
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.Core/GlobalSettings.cs View File

@ -8,6 +8,10 @@
public const string BasketEndpoint = "http://104.40.62.65:5103/";
public const string IdentityEndpoint = "http://104.40.62.65:5105/";
public const string IdentityEndpoint = "http://104.40.62.65:5105/connect/authorize";
public const string LogoutEndpoint = "http://104.40.62.65:5105/connect/endsession";
public const string IdentityCallback = "http://localhost:5003/callback.html";
}
}

+ 8
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IIdentityService.cs View File

@ -0,0 +1,8 @@
namespace eShopOnContainers.Core.Services.Identity
{
public interface IIdentityService
{
string CreateAuthorizeRequest();
string DecodeToken(string token);
}
}

+ 61
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Identity/IdentityService.cs View File

@ -0,0 +1,61 @@
using IdentityModel.Client;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace eShopOnContainers.Core.Services.Identity
{
public class IdentityService : IIdentityService
{
public string CreateAuthorizeRequest()
{
// Create URI to authorize endpoint
var authorizeRequest =
new AuthorizeRequest(GlobalSetting.IdentityEndpoint);
// Dictionary with values for the authorize request
var dic = new Dictionary<string, string>();
dic.Add("client_id", "js");
dic.Add("response_type", "id_token token");
dic.Add("scope", "openid profile basket");
dic.Add("redirect_uri", GlobalSetting.IdentityCallback);
dic.Add("nonce", Guid.NewGuid().ToString("N"));
// Add CSRF token to protect against cross-site request forgery attacks.
var currentCSRFToken = Guid.NewGuid().ToString("N");
dic.Add("state", currentCSRFToken);
var authorizeUri = authorizeRequest.Create(dic);
return authorizeUri;
}
public string DecodeToken(string token)
{
var parts = token.Split('.');
string partToConvert = parts[1];
partToConvert = partToConvert.Replace('-', '+');
partToConvert = partToConvert.Replace('_', '/');
switch (partToConvert.Length % 4)
{
case 0:
break;
case 2:
partToConvert += "==";
break;
case 3:
partToConvert += "=";
break;
}
var partAsBytes = Convert.FromBase64String(partToConvert);
var partAsUTF8String = Encoding.UTF8.GetString(partAsBytes, 0, partAsBytes.Count());
return JObject.Parse(partAsUTF8String).ToString();
}
}
}

+ 2
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs View File

@ -7,6 +7,7 @@ using eShopOnContainers.Core.Services.OpenUrl;
using eShopOnContainers.Core.Services.User;
using eShopOnContainers.Core.Services.RequestProvider;
using eShopOnContainers.Core.Services.Basket;
using eShopOnContainers.Core.Services.Identity;
namespace eShopOnContainers.ViewModels.Base
{
@ -37,6 +38,7 @@ namespace eShopOnContainers.ViewModels.Base
RegisterSingleton<INavigationService, NavigationService>();
_unityContainer.RegisterType<IOpenUrlService, OpenUrlService>();
_unityContainer.RegisterType<IRequestProvider, RequestProvider>();
_unityContainer.RegisterType<IIdentityService, IdentityService>();
_unityContainer.RegisterType<ICatalogService, CatalogMockService>();
_unityContainer.RegisterType<IBasketService, BasketMockService>();


+ 78
- 3
src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs View File

@ -1,6 +1,8 @@
using eShopOnContainers.Core.Services.OpenUrl;
using eShopOnContainers.Core.Services.Identity;
using eShopOnContainers.Core.Services.OpenUrl;
using eShopOnContainers.Core.Validations;
using eShopOnContainers.ViewModels.Base;
using IdentityModel.Client;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
@ -13,13 +15,18 @@ namespace eShopOnContainers.Core.ViewModels
{
private ValidatableObject<string> _userName;
private ValidatableObject<string> _password;
private bool _isMock;
private bool _isValid;
private string _loginUrl;
private IOpenUrlService _openUrlService;
private IIdentityService _identityService;
public LoginViewModel(IOpenUrlService openUrlService)
public LoginViewModel(IOpenUrlService openUrlService,
IIdentityService identityService)
{
_openUrlService = openUrlService;
_identityService = identityService;
_userName = new ValidatableObject<string>();
_password = new ValidatableObject<string>();
@ -53,6 +60,19 @@ namespace eShopOnContainers.Core.ViewModels
}
}
public bool IsMock
{
get
{
return _isMock;
}
set
{
_isMock = value;
RaisePropertyChanged(() => IsMock);
}
}
public bool IsValid
{
get
@ -66,11 +86,35 @@ namespace eShopOnContainers.Core.ViewModels
}
}
public string LoginUrl
{
get
{
return _loginUrl;
}
set
{
_loginUrl = value;
RaisePropertyChanged(() => LoginUrl);
}
}
public ICommand MockSignInCommand => new Command(MockSignInAsync);
public ICommand SignInCommand => new Command(SignInAsync);
public ICommand RegisterCommand => new Command(Register);
private async void SignInAsync()
public ICommand NavigateCommand => new Command<string>(NavigateAsync);
public override Task InitializeAsync(object navigationData)
{
LoginUrl = _identityService.CreateAuthorizeRequest();
return base.InitializeAsync(navigationData);
}
private async void MockSignInAsync()
{
IsBusy = true;
IsValid = true;
@ -104,11 +148,42 @@ namespace eShopOnContainers.Core.ViewModels
IsBusy = false;
}
private async void SignInAsync()
{
IsBusy = true;
await Task.Delay(500);
IsValid = true;
IsBusy = false;
}
private void Register()
{
_openUrlService.OpenUrl(GlobalSetting.RegisterWebsite);
}
private async void NavigateAsync(string url)
{
if (url.Contains(GlobalSetting.IdentityCallback))
{
// Parse response
var authResponse = new AuthorizeResponse(url);
if (!string.IsNullOrWhiteSpace(authResponse.AccessToken))
{
string decodedTokens = _identityService.DecodeToken(authResponse.AccessToken);
if(decodedTokens != null)
{
await NavigationService.NavigateToAsync<MainViewModel>();
await NavigationService.RemoveLastFromBackStackAsync();
}
}
}
}
private bool Validate()
{
bool isValidUser = _userName.Validate();


+ 49
- 2
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/LoginView.xaml View File

@ -3,7 +3,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.LoginView"
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
Title="eShop on Containers">
<ContentPage.Resources>
<ResourceDictionary>
@ -46,6 +47,20 @@
Value="Center" />
</Style>
<Style x:Key="LoginPanelStyle"
TargetType="{x:Type Grid}">
<Setter Property="HeightRequest"
Value="60" />
<Setter Property="BackgroundColor"
Value="{StaticResource LightGreenColor}" />
<Setter Property="HorizontalOptions"
Value="FillAndExpand" />
<Setter Property="VerticalOptions"
Value="Center" />
<Setter Property="Margin"
Value="12" />
</Style>
<animations:StoryBoard
x:Key="LoginAnimation"
Target="{x:Reference LoginPanel}">
@ -65,8 +80,10 @@
</ContentPage.Triggers>
<Grid
BackgroundColor="{StaticResource BackgroundColor}">
<!-- MOCK AUTH -->
<Grid
x:Name="LoginPanel"
x:Name="LoginPanel"
IsVisible="{Binding IsMock}"
Padding="0"
ColumnSpacing="0"
RowSpacing="0">
@ -154,6 +171,22 @@
Padding="0"
ColumnSpacing="0"
RowSpacing="0">
<Label
Text="[ LOGIN ]"
Style="{StaticResource LoginButtonStyle}"/>
<Grid.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding MockSignInCommand}"
NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
</Grid>
</Grid>
<!-- AUTH -->
<Grid
IsVisible="{Binding IsMock, Converter={StaticResource InverseBoolConverter}}">
<!-- LOGIN BUTTON -->
<Grid
Style="{StaticResource LoginPanelStyle}">
<Label
Text="[ LOGIN ]"
Style="{StaticResource LoginButtonStyle}"/>
@ -163,6 +196,20 @@
NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
</Grid>
<!-- WEBVIEW -->
<AbsoluteLayout
IsVisible="{Binding IsValid}">
<WebView
x:Name="AuthWebView"
Source="{Binding LoginUrl}"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
AbsoluteLayout.LayoutFlags="All">
<WebView.Behaviors>
<behaviors:WebViewNavigationBehavior
NavigateCommand="{Binding NavigateCommand}"/>
</WebView.Behaviors>
</WebView>
</AbsoluteLayout>
</Grid>
<!-- INDICATOR -->
<ActivityIndicator


+ 19
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/LoginView.xaml.cs View File

@ -8,5 +8,24 @@ namespace eShopOnContainers.Core.Views
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
AuthWebView.Navigating += OnAuthWebViewNavigating;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
AuthWebView.Navigating -= OnAuthWebViewNavigating;
}
private void OnAuthWebViewNavigating(object sender, WebNavigatingEventArgs e)
{
}
}
}

+ 7
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj View File

@ -44,6 +44,7 @@
</Compile>
<Compile Include="Behaviors\Base\BindableBehavior.cs" />
<Compile Include="Behaviors\EventToCommandBehavior.cs" />
<Compile Include="Behaviors\WebViewNavigationBehavior.cs" />
<Compile Include="Controls\BindablePicker.cs" />
<Compile Include="Controls\AddBasketButton.xaml.cs">
<DependentUpon>AddBasketButton.xaml</DependentUpon>
@ -80,6 +81,8 @@
<Compile Include="Services\Catalog\CatalogService.cs" />
<Compile Include="Services\Dialog\DialogService.cs" />
<Compile Include="Services\Dialog\IDialogService.cs" />
<Compile Include="Services\Identity\IdentityService.cs" />
<Compile Include="Services\Identity\IIdentityService.cs" />
<Compile Include="Services\Navigation\INavigationService.cs" />
<Compile Include="Services\Navigation\NavigationService.cs" />
<Compile Include="Services\OpenUrl\IOpenUrlService.cs" />
@ -186,6 +189,10 @@
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.6-pre-232\lib\portable-net45+win8+wpa81+wp8\FFImageLoading.Platform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="IdentityModel, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\IdentityModel.1.13.1\lib\portable-net45+wp80+win8+wpa81\IdentityModel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
<Private>True</Private>


+ 1
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/packages.config View File

@ -2,6 +2,7 @@
<packages>
<package id="Acr.UserDialogs" version="6.3.1" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="CommonServiceLocator" version="1.3" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="IdentityModel" version="1.13.1" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="portable45-net45+win8+wp8+wpa81" />


+ 1
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj View File

@ -17,7 +17,7 @@
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />


+ 5
- 8
src/Mobile/eShopOnContainers/eShopOnContainers.Droid/eShopOnContainers.Droid.csproj.bak View File

@ -17,7 +17,7 @@
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
@ -223,6 +223,8 @@
<None Include="packages.config" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<AndroidResource Include="Resources\drawable-xxhdpi\switch_off.png" />
<AndroidResource Include="Resources\drawable-xxhdpi\switch_on.png" />
<AndroidResource Include="Resources\layout\Tabs.axml">
<SubType>Designer</SubType>
</AndroidResource>
@ -332,9 +334,6 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\switch_on.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\switch_on.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\switch_off.png" />
</ItemGroup>
@ -342,10 +341,10 @@
<AndroidResource Include="Resources\drawable-xhdpi\switch_off.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\switch_off.png" />
<AndroidResource Include="Resources\drawable\noimage.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\noimage.png" />
<AndroidResource Include="Resources\drawable\default_product.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
@ -354,9 +353,7 @@
<ErrorText>Este proyecto hace referencia a los paquetes NuGet que faltan en este equipo. Use la restauración de paquetes NuGet para descargarlos. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=322105. El archivo que falta es {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\..\packages\StyleCop.MSBuild.5.0.0-alpha01\build\StyleCop.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\StyleCop.MSBuild.5.0.0-alpha01\build\StyleCop.MSBuild.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
</Target>
<Import Project="..\..\packages\StyleCop.MSBuild.5.0.0-alpha01\build\StyleCop.MSBuild.targets" Condition="Exists('..\..\packages\StyleCop.MSBuild.5.0.0-alpha01\build\StyleCop.MSBuild.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
</Project>

Loading…
Cancel
Save