Skip to content

Commit

Permalink
Merge pull request #32 from SSchulze1989/featue/id-access-token
Browse files Browse the repository at this point in the history
Implement access token handling
  • Loading branch information
SSchulze1989 authored Jan 24, 2023
2 parents 7ca7162 + 0bbc521 commit 1e5c9e7
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 30 deletions.
66 changes: 48 additions & 18 deletions src/iRLeagueManager.Web/Data/AsyncTokenStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,45 @@ internal sealed class AsyncTokenStore : ITokenStore
private readonly ILogger<AsyncTokenStore> logger;
private readonly ProtectedLocalStorage localStore;

private const string tokenKey = "LeagueApiToken";
private const string tokenKey = "idToken";

private string inMemoryToken = string.Empty;
private string inMemoryIdToken = string.Empty;
private string inMemoryAccessToken = string.Empty;

public event EventHandler? TokenChanged;
public event EventHandler? TokenExpired;

public bool IsLoggedIn { get; private set; }
public DateTime Expiration { get; private set; }
private bool AccessTokenExpired { get; set; } = false;
public DateTime IdTokenExpires { get; private set; }
public DateTime AccessTokenExpires { get; private set; }

public AsyncTokenStore(ILogger<AsyncTokenStore> logger, ProtectedLocalStorage localStorage)
{
this.logger = logger;
this.localStore = localStorage;
}

public async Task ClearTokenAsync()
public async Task ClearTokensAsync()
{
var tokenValue = inMemoryToken;
var tokenValue = inMemoryIdToken;

logger.LogDebug("Clear token in local browser store");
IsLoggedIn = false;
inMemoryToken = string.Empty;
inMemoryIdToken = string.Empty;
await localStore.DeleteAsync(tokenKey);
await Task.FromResult(true);
if (inMemoryToken != tokenValue)
if (inMemoryIdToken != tokenValue)
{
TokenChanged?.Invoke(this, EventArgs.Empty);
}
}

public async Task<string> GetTokenAsync()
public async Task<string> GetIdTokenAsync()
{
if (string.IsNullOrEmpty(inMemoryToken) == false)
if (string.IsNullOrEmpty(inMemoryIdToken) == false)
{
return inMemoryToken;
return inMemoryIdToken;
}

logger.LogDebug("Reading token from local browser store");
Expand All @@ -65,19 +69,19 @@ public async Task<string> GetTokenAsync()
if (jsonToken.Claims.Any(x => x.Type == "exp"))
{
var expSeconds = Convert.ToInt64(jsonToken.Claims.First(x => x.Type == "exp").Value);
Expiration = new DateTime(1970, 1, 1).AddSeconds(expSeconds);
IdTokenExpires = new DateTime(1970, 1, 1).AddSeconds(expSeconds);
}
}

// check if token is still valid
if (Expiration < DateTime.UtcNow.AddMinutes(5))
if (IdTokenExpires < DateTime.UtcNow.AddMinutes(5))
{
await ClearTokenAsync();
await ClearTokensAsync();
logger.LogInformation("Token read from token store has expired");
return string.Empty;
}
IsLoggedIn = true;
return inMemoryToken = token.Value ?? string.Empty;
return inMemoryIdToken = token.Value ?? string.Empty;
}
IsLoggedIn = false;
return string.Empty;
Expand All @@ -89,16 +93,42 @@ public async Task<string> GetTokenAsync()
}
}

public async Task SetTokenAsync(string token)
public async Task SetIdTokenAsync(string token)
{
var oldToken = inMemoryToken;
var oldToken = inMemoryIdToken;
logger.LogDebug("Set token to local browser session: {Token}", token);
await localStore.SetAsync(tokenKey, token);
inMemoryToken = token;
inMemoryIdToken = token;

if (inMemoryToken != oldToken)
if (inMemoryIdToken != oldToken)
{
TokenChanged?.Invoke(this, EventArgs.Empty);
}
}

public async Task SetAccessTokenAsync(string token)
{
inMemoryAccessToken = token;
AccessTokenExpired = false;

if (string.IsNullOrEmpty(inMemoryAccessToken) == false)
{
// set expiration date
var jwtToken = new JwtSecurityTokenHandler().ReadToken(inMemoryAccessToken);
AccessTokenExpires = jwtToken.ValidTo;
}

TokenChanged?.Invoke(this, EventArgs.Empty);
await Task.CompletedTask;
}

public async Task<string> GetAccessTokenAsync()
{
if (AccessTokenExpires <= DateTime.UtcNow && string.IsNullOrEmpty(inMemoryAccessToken) == false && AccessTokenExpired == false)
{
AccessTokenExpired = true;
TokenExpired?.Invoke(this, EventArgs.Empty);
}
return await Task.FromResult(inMemoryAccessToken);
}
}
2 changes: 1 addition & 1 deletion src/iRLeagueManager.Web/Pages/Member/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (string.IsNullOrEmpty(await tokenStore.GetTokenAsync()) == false)
if (string.IsNullOrEmpty(await tokenStore.GetAccessTokenAsync()) == false)
{
var returnUrl = NavigationManager.QueryString("returnUrl") ?? "";
NavigationManager.NavigateTo(returnUrl);
Expand Down
11 changes: 8 additions & 3 deletions src/iRLeagueManager.Web/Shared/JwtAuthenticationStateProvicer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ private void TokenStore_TokenChanged(object? sender, EventArgs e)

private async Task<ClaimsPrincipal> GetTokenUser()
{
var token = await tokenStore.GetTokenAsync();
if (string.IsNullOrEmpty(token))
var idToken = await tokenStore.GetIdTokenAsync();
if (string.IsNullOrEmpty(idToken))
{
return GetAnonymous();
}
var jwtSecurityToken = tokenHandler.ReadJwtToken(token);
var accessToken = await tokenStore.GetAccessTokenAsync();
if (string.IsNullOrEmpty(accessToken))
{
return GetAnonymous();
}
var jwtSecurityToken = tokenHandler.ReadJwtToken(accessToken);
var identity = new ClaimsIdentity(jwtSecurityToken.Claims, "bearer");
return new ClaimsPrincipal(identity);
}
Expand Down
4 changes: 2 additions & 2 deletions src/iRLeagueManager.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
}
},
"AllowedHosts": "*",
//"APIServer": "http://localhost:5000",
"APIServer": "https://irleaguemanager.net/api/",
"APIServer": "http://localhost:5000",
//"APIServer": "https://irleaguemanager.net/api/",
"DefaultUser": "testuser",
"DefaultPassword": "TestPass123!"
}
8 changes: 2 additions & 6 deletions src/iRLeagueManager.Web/iRLeagueManager.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,12 @@
<Content Include="Components\Reviews\ReviewCard.razor.css" />
</ItemGroup>

<ItemGroup>
<None Include="compilerconfig.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="bootstrap.sass" Version="5.2.3" />
<PackageReference Include="iRLeagueApiCore.Client" Version="0.4.1" />
<PackageReference Include="iRLeagueApiCore.Common" Version="0.4.1" />
<PackageReference Include="iRLeagueApiCore.Client" Version="0.4.2-dev.3" />
<PackageReference Include="iRLeagueApiCore.Common" Version="0.4.2-dev.1" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.3" />
Expand Down

0 comments on commit 1e5c9e7

Please sign in to comment.