forked from dotnet-architecture/eShopOnWeb
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Blazor WebAssembly Admin Page (dotnet-architecture#426)
* Added Blazor Client Configured PublicAPI CORS to allow traffic from client * Make admin page home page; remove extra pages Add CatalogType list endpoint * Wired up Types and Brands in the API and the admin list page * Adding a custom HttpClient to talk securely to API * Ardalis/blazor (dotnet-architecture#419) * Login added * AuthService will handel http request secure and not secure. * Logout added * CatalogBrandService in it is own service * Get token from localstorage when refresh. * used GetAsync * Fixed Login and Logout switch. * CatalogItemService added * CatalogTypeService added & Auth for CatalogType. using not used removed. * Made BlazorComponent and BlazorLayoutComponent for refresh. Index now small enough to be in one file. * Removed the service from program main and use lazy singleton. * used OnInitialized * Refactoring and detecting login status in login.razor * Refactoring login to redirect if user is already logged in * Blazor login with MVC (dotnet-architecture#420) * Blazor login with MVC * return back the PasswordSignInAsync in Login page * CRUD added (dotnet-architecture#422) * CRUD added * Unit Test changed to meet new redirect /admin * CreateCatalogItemRequest added. * Action caption added. * Validation added for name and price. * Updated port of api Redirect to returnUrl from login * Add username to /admin; link to my profile * Working on authorization of /admin * Working on custom auth locking down /admin page * Microsoft authorize working.Login.razor removed.Login from SignInMana… (dotnet-architecture#425) * Microsoft authorize working.Login.razor removed.Login from SignInManager and create token from it.unit test fixed. * GetTokenFromController function used in CustomAuthStateProvider * Cleaned up button styles Refactored to use codebehind for List component Updated Not Authorized view Co-authored-by: Shady Nagy <shadynagi@gmail.com>
- Loading branch information
Showing
86 changed files
with
3,266 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<CascadingAuthenticationState> | ||
<Router AppAssembly="@typeof(Program).Assembly"> | ||
<Found Context="routeData"> | ||
<AuthorizeRouteView RouteData="@routeData" | ||
DefaultLayout="@typeof(MainLayout)"> | ||
<NotAuthorized> | ||
@if (!context.User.Identity.IsAuthenticated) | ||
{ | ||
<RedirectToLogin /> | ||
} | ||
else | ||
{ | ||
<h2>Not Authorized</h2> | ||
<p> | ||
You are not authorized to access | ||
this resource. | ||
|
||
<a href="/">Return to eShop</a> | ||
</p> | ||
} | ||
</NotAuthorized> | ||
</AuthorizeRouteView> | ||
</Found> | ||
<NotFound> | ||
<LayoutView Layout="@typeof(MainLayout)"> | ||
<p>Sorry, there's nothing at this address.</p> | ||
</LayoutView> | ||
</NotFound> | ||
</Router> | ||
</CascadingAuthenticationState> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.1</TargetFramework> | ||
<RazorLangVersion>3.0</RazorLangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Blazored.LocalStorage" Version="2.1.6" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.5" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="3.2.0" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" PrivateAssets="all" /> | ||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="3.1.5" /> | ||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" /> | ||
<PackageReference Include="System.Net.Http.Json" Version="3.2.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" /> | ||
<ProjectReference Include="..\Shared\Shared.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Compile Update="Services\CatalogItem\Delete.EditCatalogItemResult.cs"> | ||
<DependentUpon>Delete.cs</DependentUpon> | ||
</Compile> | ||
<Compile Update="Services\CatalogItem\GetById.EditCatalogItemResult.cs"> | ||
<DependentUpon>GetById.cs</DependentUpon> | ||
</Compile> | ||
<Compile Update="Services\CatalogItem\Edit.CreateCatalogItemResult.cs"> | ||
<DependentUpon>Edit.cs</DependentUpon> | ||
</Compile> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace BlazorAdmin | ||
{ | ||
public class Constants | ||
{ | ||
public const string API_URL = "https://localhost:5099/api/"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using System; | ||
using System.Net.Http; | ||
using System.Net.Http.Json; | ||
using BlazorAdmin.Services; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Components.Authorization; | ||
using System.Security.Claims; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.eShopWeb; | ||
using Microsoft.Extensions.Logging; | ||
using Shared.Authorization; | ||
|
||
namespace BlazorAdmin | ||
{ | ||
public class CustomAuthStateProvider : AuthenticationStateProvider | ||
{ | ||
private static readonly TimeSpan UserCacheRefreshInterval = TimeSpan.FromSeconds(60); | ||
|
||
private readonly AuthService _authService; | ||
private readonly ILogger<CustomAuthStateProvider> _logger; | ||
|
||
private DateTimeOffset _userLastCheck = DateTimeOffset.FromUnixTimeSeconds(0); | ||
private ClaimsPrincipal _cachedUser = new ClaimsPrincipal(new ClaimsIdentity()); | ||
|
||
public CustomAuthStateProvider(AuthService authService, ILogger<CustomAuthStateProvider> logger) | ||
{ | ||
_authService = authService; | ||
_logger = logger; | ||
} | ||
|
||
public override async Task<AuthenticationState> GetAuthenticationStateAsync() => | ||
new AuthenticationState(await GetUser(useCache: true)); | ||
|
||
private async ValueTask<ClaimsPrincipal> GetUser(bool useCache = false) | ||
{ | ||
var now = DateTimeOffset.Now; | ||
if (useCache && now < _userLastCheck + UserCacheRefreshInterval) | ||
{ | ||
return _cachedUser; | ||
} | ||
|
||
_cachedUser = await FetchUser(); | ||
_userLastCheck = now; | ||
|
||
return _cachedUser; | ||
} | ||
|
||
private async Task<ClaimsPrincipal> FetchUser() | ||
{ | ||
UserInfo user = null; | ||
|
||
try | ||
{ | ||
user = await _authService.GetTokenFromController(); | ||
} | ||
catch (Exception exc) | ||
{ | ||
_logger.LogWarning(exc, "Fetching user failed."); | ||
} | ||
|
||
if (user == null || !user.IsAuthenticated) | ||
{ | ||
return new ClaimsPrincipal(new ClaimsIdentity()); | ||
} | ||
|
||
var identity = new ClaimsIdentity( | ||
nameof(CustomAuthStateProvider), | ||
user.NameClaimType, | ||
user.RoleClaimType); | ||
|
||
if (user.Claims != null) | ||
{ | ||
foreach (var claim in user.Claims) | ||
{ | ||
identity.AddClaim(new Claim(claim.Type, claim.Value)); | ||
} | ||
} | ||
|
||
return new ClaimsPrincipal(identity); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Microsoft.AspNetCore.Components; | ||
|
||
namespace BlazorAdmin.Helpers | ||
{ | ||
public class BlazorComponent : ComponentBase | ||
{ | ||
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; | ||
|
||
protected override void OnInitialized() | ||
{ | ||
_refresh.RefreshRequested += DoRefresh; | ||
base.OnInitialized(); | ||
} | ||
|
||
public void CallRequestRefresh() | ||
{ | ||
_refresh.CallRequestRefresh(); | ||
} | ||
|
||
private void DoRefresh() | ||
{ | ||
StateHasChanged(); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System.Threading.Tasks; | ||
using BlazorAdmin.Services; | ||
using Microsoft.AspNetCore.Components; | ||
|
||
namespace BlazorAdmin.Helpers | ||
{ | ||
public class BlazorLayoutComponent : LayoutComponentBase | ||
{ | ||
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; | ||
|
||
protected override void OnInitialized() | ||
{ | ||
_refresh.RefreshRequested += DoRefresh; | ||
base.OnInitialized(); | ||
} | ||
|
||
public void CallRequestRefresh() | ||
{ | ||
_refresh.CallRequestRefresh(); | ||
} | ||
|
||
private void DoRefresh() | ||
{ | ||
StateHasChanged(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
|
||
namespace BlazorAdmin.Helpers | ||
{ | ||
internal sealed class RefreshBroadcast | ||
{ | ||
private static readonly Lazy<RefreshBroadcast> | ||
Lazy = | ||
new Lazy<RefreshBroadcast> | ||
(() => new RefreshBroadcast()); | ||
|
||
public static RefreshBroadcast Instance => Lazy.Value; | ||
|
||
private RefreshBroadcast() | ||
{ | ||
} | ||
|
||
public event Action RefreshRequested; | ||
public void CallRequestRefresh() | ||
{ | ||
RefreshRequested?.Invoke(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.JSInterop; | ||
|
||
namespace BlazorAdmin.JavaScript | ||
{ | ||
public class Cookies | ||
{ | ||
private readonly IJSRuntime _jsRuntime; | ||
|
||
public Cookies(IJSRuntime jsRuntime) | ||
{ | ||
_jsRuntime = jsRuntime; | ||
} | ||
|
||
public async Task DeleteCookie(string name) | ||
{ | ||
await _jsRuntime.InvokeAsync<string>("deleteCookie", name); | ||
} | ||
|
||
public async Task<string> GetCookie(string name) | ||
{ | ||
return await _jsRuntime.InvokeAsync<string>("getCookie", name); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.JSInterop; | ||
|
||
namespace BlazorAdmin.JavaScript | ||
{ | ||
public class Route | ||
{ | ||
private readonly IJSRuntime _jsRuntime; | ||
|
||
public Route(IJSRuntime jsRuntime) | ||
{ | ||
_jsRuntime = jsRuntime; | ||
} | ||
|
||
public async Task RouteOutside(string path) | ||
{ | ||
await _jsRuntime.InvokeAsync<string>("routeOutside", path); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; | ||
using System.Collections.Generic; | ||
using System.Net.Http; | ||
using System.Net.Http.Json; | ||
using System.Threading.Tasks; | ||
using BlazorAdmin.Services.CatalogBrandService; | ||
|
||
namespace BlazorAdmin.Network | ||
{ | ||
public class SecureHttpClient | ||
{ | ||
private readonly HttpClient client; | ||
|
||
public SecureHttpClient(HttpClient client) | ||
{ | ||
this.client = client; | ||
|
||
this.client.DefaultRequestHeaders.Add("Authorization", $"Bearer "); | ||
} | ||
|
||
public async Task<List<CatalogBrand>> GetCatalogBrandsAsync() | ||
{ | ||
var brands = new List<CatalogBrand>(); | ||
|
||
try | ||
{ | ||
brands = (await client.GetFromJsonAsync<CatalogBrandResult>($"{Constants.API_URL}catalog-brands")).CatalogBrands; | ||
} | ||
catch (AccessTokenNotAvailableException exception) | ||
{ | ||
exception.Redirect(); | ||
} | ||
|
||
return brands; | ||
} | ||
} | ||
} |
Oops, something went wrong.