Hi Guys!
It's been a while since I've been here, but I finally found the time to continue working and improving my app. One of these improvements is implementing an Identityserver instance to manage the authentication.
Using the following topics I got this working;
- https://www.scottbrady91.com/Identity-Server/Getting-Started-with-IdentityServer-4
- https://sinclairinat0r.com/2018/12/09/secure-data-access-with-identityserver4-and-xamarin-forms
- https://ngohungphuc.wordpress.com/2018/12/11/identity-server-4-with-asp-net-core-2-2/
Since my login procedure is a little bit different from what the examples are showing, I implemented a page with a Login and Registration button. The login works, but after Identityserver redirects me to my app and all the account information is stored, I'm getting a blank page. When I restart my app I immediately get the MainPage which I want to see, because I have a valid account stored.
My SignIn page shows a login and registration button. The loginbutton triggers an oAuthLoginPage which uses a PageRenderer. The code looks like this for my oAuthLoginpage, it's just a C# class;
public class OAuthLoginPage : ContentPage
{
public static event EventHandler LoginSucceeded;
public static event EventHandler LoginCancelled;
public static void LoginSuccess(object sender)
{
if (LoginSucceeded == null) throw new InvalidOperationException();
//Invoked and then sent to the App.cs
LoginSucceeded(sender, EventArgs.Empty);
}
public static void LoginCancel(object sender)
{
if (LoginCancelled == null) throw new InvalidOperationException();
//Invoked and then sent to the App.cs
LoginCancelled(sender, EventArgs.Empty);
}
}
The renderer looks like this;
[assembly: ExportRenderer(typeof(OAuthLoginPage), typeof(OAuthLoginPageRenderer))]
namespace MyApp.Droid.Renderers
{
public class OAuthLoginPageRenderer : PageRenderer
{
public OAuthLoginPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
string idservRootPath = "https://MyApp-idp-o.azurewebsites.net";
var oAuth = new OAuth2AuthenticatorEx("MyApp.app"
, "openid profile"
, new Uri($"{idservRootPath}/connect/authorize")
, new Uri("com.MyApp.app:/oauth2redirect")
, isUsingNativeUI:false)
{
AccessTokenUrl = new Uri($"{idservRootPath}/connect/token"),
ShouldEncounterOnPageLoading = false
};
var account = Task.Run(async () => await App.GetCurrentUserAccountAsync(Serviceconstants.oAuthAccountServiceId)).ConfigureAwait(false)
.GetAwaiter()
.GetResult();
if (account != null)
{
App.AuthAccount = account;
App.HttpClient.AddDefaultRequestHeaderIfNotExists("Authorization", $"Bearer {account.Properties["access_token"]}");
OAuthLoginPage.LoginSuccess(null);
}
else
{
oAuth.Completed += Presenter_Completed;
oAuth.Error += Presenter_Error;
var presenter = new OAuthLoginPresenter();
presenter.Completed += Presenter_Completed;
presenter.Login(oAuth);
}
}
private void Presenter_Error(object sender, AuthenticatorErrorEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Message))
{
}
}
private void Presenter_Completed(object sender, AuthenticatorCompletedEventArgs e)
{
if (e.IsAuthenticated)
{
App.AuthAccount = e.Account;
App.HttpClient.AddDefaultRequestHeaderIfNotExists("Authorization", $"Bearer {App.AuthAccount.Properties["access_token"]}");
Task.Run(async () => await App.SaveAccountAsync(e.Account, Serviceconstants.oAuthAccountServiceId).ConfigureAwait(false));
OAuthLoginPage.LoginSuccess(sender);
}
}
}
}
As you can see when the login is a succes, and event is being used to trigger the redirect to the mainpage. This happens in the App itsself;
public App()
{
InitializeComponent();
//Events fired from the LoginPage to trigger actions here
OAuthLoginPage.LoginSucceeded += HandleLoginSucceeded;
OAuthLoginPage.LoginCancelled += CancelLoginAction;
MainPage = new MainPage();
}
and
private void HandleLoginSucceeded(object sender, EventArgs e)
{
//awaits writing token to storage and resets the MainPage UI
StoreToken();
_accountHasBeenInvalidated = false;
MainPage = new MainPage();
}
private void CancelLoginAction(object sender, EventArgs e)
{
//if login cancelled, user will be redirected back to the sign-in page
MainPage = new NavigationPage(new SignIn());
}
I can't get my head around the fact that I keep getting a blank page, does anybody have any idea what this could be?