Browse Source

Code cleanup

main
Steve Smith 5 years ago
parent
commit
b30b0c2eef
  1. 2
      README.md
  2. 2
      docker-compose.override.yml
  3. 12
      eShopOnWeb.sln
  4. 4
      src/ApplicationCore/ApplicationCore.csproj
  5. 4
      src/ApplicationCore/Constants/AuthorizationConstants.cs
  6. 2
      src/BlazorAdmin/BlazorAdmin.csproj
  7. 12
      src/BlazorAdmin/Constants.cs
  8. 2
      src/BlazorAdmin/CustomAuthStateProvider.cs
  9. 4
      src/BlazorAdmin/JavaScript/Cookies.cs
  10. 14
      src/BlazorAdmin/JavaScript/JSInteropConstants.cs
  11. 2
      src/BlazorAdmin/JavaScript/Route.cs
  12. 2
      src/BlazorAdmin/Pages/CatalogItemPage/Create.razor
  13. 8
      src/BlazorAdmin/Pages/CatalogItemPage/Delete.razor
  14. 6
      src/BlazorAdmin/Pages/CatalogItemPage/Details.razor
  15. 2
      src/BlazorAdmin/Pages/CatalogItemPage/Edit.razor
  16. 9
      src/BlazorAdmin/Pages/CatalogItemPage/List.razor
  17. 14
      src/BlazorAdmin/Pages/CatalogItemPage/List.razor.cs
  18. 185
      src/BlazorAdmin/Services/AuthService.cs
  19. 2
      src/BlazorAdmin/Services/CatalogBrandServices/List.CatalogBrand.cs
  20. 2
      src/BlazorAdmin/Services/CatalogBrandServices/List.CatalogBrandResult.cs
  21. 4
      src/BlazorAdmin/Services/CatalogBrandServices/List.cs
  22. 2
      src/BlazorAdmin/Services/CatalogItemServices/CatalogItem.cs
  23. 2
      src/BlazorAdmin/Services/CatalogItemServices/Create.CreateCatalogItemRequest.cs
  24. 2
      src/BlazorAdmin/Services/CatalogItemServices/Create.CreateCatalogItemResult.cs
  25. 8
      src/BlazorAdmin/Services/CatalogItemServices/Create.cs
  26. 2
      src/BlazorAdmin/Services/CatalogItemServices/Delete.DeleteCatalogItemResult.cs
  27. 4
      src/BlazorAdmin/Services/CatalogItemServices/Delete.cs
  28. 2
      src/BlazorAdmin/Services/CatalogItemServices/Edit.EditCatalogItemResult.cs
  29. 8
      src/BlazorAdmin/Services/CatalogItemServices/Edit.cs
  30. 2
      src/BlazorAdmin/Services/CatalogItemServices/GetById.GetByIdCatalogItemResult.cs
  31. 4
      src/BlazorAdmin/Services/CatalogItemServices/GetById.cs
  32. 2
      src/BlazorAdmin/Services/CatalogItemServices/ListPaged.PagedCatalogItemResult.cs
  33. 4
      src/BlazorAdmin/Services/CatalogItemServices/ListPaged.cs
  34. 2
      src/BlazorAdmin/Services/CatalogTypeServices/List.CatalogType.cs
  35. 2
      src/BlazorAdmin/Services/CatalogTypeServices/List.CatalogTypeResult.cs
  36. 4
      src/BlazorAdmin/Services/CatalogTypeServices/List.cs
  37. 2
      src/BlazorAdmin/Shared/MainLayout.razor
  38. 6
      src/BlazorAdmin/Shared/NavMenu.razor
  39. 2
      src/BlazorAdmin/Shared/RedirectToLogin.razor
  40. 9
      src/BlazorAdmin/_Imports.razor
  41. 5
      src/BlazorAdmin/wwwroot/css/admin.css
  42. 2
      src/BlazorShared/Authorization/ClaimValue.cs
  43. 25
      src/BlazorShared/Authorization/Constants.cs
  44. 2
      src/BlazorShared/Authorization/UserInfo.cs
  45. 9
      src/BlazorShared/BlazorShared.csproj
  46. 4
      src/Infrastructure/Identity/AppIdentityDbContextSeed.cs
  47. 2
      src/PublicApi/CatalogItemEndpoints/Create.cs
  48. 2
      src/PublicApi/CatalogItemEndpoints/Delete.cs
  49. 2
      src/PublicApi/CatalogItemEndpoints/Update.cs
  50. 6
      src/PublicApi/Startup.cs
  51. 7
      src/Shared/Shared.csproj
  52. 5
      src/Web/Areas/Identity/Pages/Account/Login.cshtml.cs
  53. 6
      src/Web/Configuration/ConfigureCookieSettings.cs
  54. 4
      src/Web/Configuration/ConfigureCoreServices.cs
  55. 4
      src/Web/Configuration/ConfigureWebServices.cs
  56. 2
      src/Web/Controllers/UserController.cs
  57. 2
      src/Web/Pages/Admin/EditCatalogItem.cshtml.cs
  58. 2
      src/Web/Pages/Admin/Index.cshtml.cs
  59. 40
      src/Web/Startup.cs
  60. 2
      src/Web/Web.csproj

2
README.md

@ -103,7 +103,7 @@ You can run the Web sample by running these commands from the root folder (where
docker-compose up docker-compose up
``` ```
You should be able to make requests to localhost:5106 for the Web project, and localhost:5200 for the Public API project once these commands complete. You should be able to make requests to localhost:5106 for the Web project, and localhost:5200 for the Public API project once these commands complete. If you have any problems, especially with login, try from a new guest or incognito browser instance.
You can also run the applications by using the instructions located in their `Dockerfile` file in the root of each project. Again, run these commands from the root of the solution (where the .sln file is located). You can also run the applications by using the instructions located in their `Dockerfile` file in the root of each project. Again, run these commands from the root of the solution (where the .sln file is located).

2
docker-compose.override.yml

@ -4,6 +4,7 @@ services:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:80 - ASPNETCORE_URLS=http://+:80
- DOTNET_RUNNING_IN_CONTAINER=true
ports: ports:
- "5106:80" - "5106:80"
volumes: volumes:
@ -13,6 +14,7 @@ services:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:80 - ASPNETCORE_URLS=http://+:80
- DOTNET_RUNNING_IN_CONTAINER=true
ports: ports:
- "5200:80" - "5200:80"
volumes: volumes:

12
eShopOnWeb.sln

@ -34,7 +34,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublicApi", "src\PublicApi\
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAdmin", "src\BlazorAdmin\BlazorAdmin.csproj", "{71368733-80A4-4869-B215-3A7001878577}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAdmin", "src\BlazorAdmin\BlazorAdmin.csproj", "{71368733-80A4-4869-B215-3A7001878577}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "src\Shared\Shared.csproj", "{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorShared", "src\BlazorShared\BlazorShared.csproj", "{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -78,10 +78,10 @@ Global
{71368733-80A4-4869-B215-3A7001878577}.Debug|Any CPU.Build.0 = Debug|Any CPU {71368733-80A4-4869-B215-3A7001878577}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71368733-80A4-4869-B215-3A7001878577}.Release|Any CPU.ActiveCfg = Release|Any CPU {71368733-80A4-4869-B215-3A7001878577}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71368733-80A4-4869-B215-3A7001878577}.Release|Any CPU.Build.0 = Release|Any CPU {71368733-80A4-4869-B215-3A7001878577}.Release|Any CPU.Build.0 = Release|Any CPU
{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8}.Release|Any CPU.Build.0 = Release|Any CPU {715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -95,7 +95,7 @@ Global
{7EFB5482-F942-4C3D-94B0-9B70596E6D0A} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF} {7EFB5482-F942-4C3D-94B0-9B70596E6D0A} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF}
{B5E4F33C-4667-4A55-AF6A-740F84C4CF3A} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} {B5E4F33C-4667-4A55-AF6A-740F84C4CF3A} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{71368733-80A4-4869-B215-3A7001878577} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} {71368733-80A4-4869-B215-3A7001878577} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{7BDB419E-FAC1-4D43-8AA9-FB61EBE31BB8} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} {715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B} SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B}

4
src/ApplicationCore/ApplicationCore.csproj

@ -13,4 +13,8 @@
<PackageReference Include="System.Text.Json" Version="4.7.2" /> <PackageReference Include="System.Text.Json" Version="4.7.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BlazorShared\BlazorShared.csproj" />
</ItemGroup>
</Project> </Project>

4
src/ApplicationCore/Constants/AuthorizationConstants.cs

@ -2,10 +2,6 @@
{ {
public class AuthorizationConstants public class AuthorizationConstants
{ {
public static class Roles
{
public const string ADMINISTRATORS = "Administrators";
}
// TODO: Don't use this in production // TODO: Don't use this in production
public const string DEFAULT_PASSWORD = "Pass@word1"; public const string DEFAULT_PASSWORD = "Pass@word1";

2
src/BlazorAdmin/BlazorAdmin.csproj

@ -18,7 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" /> <ProjectReference Include="..\BlazorShared\BlazorShared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

12
src/BlazorAdmin/Constants.cs

@ -1,12 +0,0 @@
namespace BlazorAdmin
{
public class Constants
{
public const string API_URL = "https://localhost:5099/api/";
public static class Roles
{
public const string ADMINISTRATORS = "Administrators";
}
}
}

2
src/BlazorAdmin/CustomAuthStateProvider.cs

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Shared.Authorization; using BlazorShared.Authorization;
namespace BlazorAdmin namespace BlazorAdmin
{ {

4
src/BlazorAdmin/JavaScript/Cookies.cs

@ -14,12 +14,12 @@ namespace BlazorAdmin.JavaScript
public async Task DeleteCookie(string name) public async Task DeleteCookie(string name)
{ {
await _jsRuntime.InvokeAsync<string>("deleteCookie", name); await _jsRuntime.InvokeAsync<string>(JSInteropConstants.DeleteCookie, name);
} }
public async Task<string> GetCookie(string name) public async Task<string> GetCookie(string name)
{ {
return await _jsRuntime.InvokeAsync<string>("getCookie", name); return await _jsRuntime.InvokeAsync<string>(JSInteropConstants.GetCookie, name);
} }
} }
} }

14
src/BlazorAdmin/JavaScript/JSInteropConstants.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorAdmin.JavaScript
{
public static class JSInteropConstants
{
public static string DeleteCookie => "deleteCookie";
public static string GetCookie => "getCookie";
public static string RouteOutside => "routeOutside";
}
}

2
src/BlazorAdmin/JavaScript/Route.cs

@ -14,7 +14,7 @@ namespace BlazorAdmin.JavaScript
public async Task RouteOutside(string path) public async Task RouteOutside(string path)
{ {
await _jsRuntime.InvokeAsync<string>("routeOutside", path); await _jsRuntime.InvokeAsync<string>(JSInteropConstants.RouteOutside, path);
} }
} }
} }

2
src/BlazorAdmin/Pages/CatalogItemPage/Create.razor

@ -118,7 +118,7 @@
private async Task CreateClick() private async Task CreateClick()
{ {
await new BlazorAdmin.Services.CatalogItemService.Create(Auth).HandleAsync(_item); await new BlazorAdmin.Services.CatalogItemServices.Create(Auth).HandleAsync(_item);
await OnCloseClick.InvokeAsync(null); await OnCloseClick.InvokeAsync(null);
Close(); Close();
} }

8
src/BlazorAdmin/Pages/CatalogItemPage/Delete.razor

@ -23,7 +23,7 @@
{ {
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<img class="col-md-6 esh-picture" src="@($"https://localhost:44315/{_item.PictureUri}")"> <img class="col-md-6 esh-picture" src="@($"{Auth.WebUrl}{_item.PictureUri}")">
<dl class="col-md-6 dl-horizontal"> <dl class="col-md-6 dl-horizontal">
<dt> <dt>
@ -47,7 +47,7 @@
</dt> </dt>
<dd> <dd>
@Services.CatalogBrandService.List.GetBrandName(Brands, _item.CatalogBrandId) @Services.CatalogBrandServices.List.GetBrandName(Brands, _item.CatalogBrandId)
</dd> </dd>
<dt> <dt>
@ -55,7 +55,7 @@
</dt> </dt>
<dd> <dd>
@Services.CatalogTypeService.List.GetTypeName(Types, _item.CatalogTypeId) @Services.CatalogTypeServices.List.GetTypeName(Types, _item.CatalogTypeId)
</dd> </dd>
<dt> <dt>
Price Price
@ -105,7 +105,7 @@
{ {
// TODO: Add some kind of "are you sure" check before this // TODO: Add some kind of "are you sure" check before this
await new BlazorAdmin.Services.CatalogItemService.Delete(Auth).HandleAsync(id); await new BlazorAdmin.Services.CatalogItemServices.Delete(Auth).HandleAsync(id);
await OnCloseClick.InvokeAsync(null); await OnCloseClick.InvokeAsync(null);
Close(); Close();

6
src/BlazorAdmin/Pages/CatalogItemPage/Details.razor

@ -26,7 +26,7 @@
{ {
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<img class="col-md-6 esh-picture" src="@($"https://localhost:44315/{_item.PictureUri}")"> <img class="col-md-6 esh-picture" src="@($"{Auth.WebUrl}{_item.PictureUri}")">
<dl class="col-md-6 dl-horizontal"> <dl class="col-md-6 dl-horizontal">
<dt> <dt>
@ -50,7 +50,7 @@
</dt> </dt>
<dd> <dd>
@Services.CatalogBrandService.List.GetBrandName(Brands, _item.CatalogBrandId) @Services.CatalogBrandServices.List.GetBrandName(Brands, _item.CatalogBrandId)
</dd> </dd>
<dt> <dt>
@ -58,7 +58,7 @@
</dt> </dt>
<dd> <dd>
@Services.CatalogTypeService.List.GetTypeName(Types, _item.CatalogTypeId) @Services.CatalogTypeServices.List.GetTypeName(Types, _item.CatalogTypeId)
</dd> </dd>
<dt> <dt>
Price Price

2
src/BlazorAdmin/Pages/CatalogItemPage/Edit.razor

@ -118,7 +118,7 @@
private async Task SaveClick() private async Task SaveClick()
{ {
await new BlazorAdmin.Services.CatalogItemService.Edit(Auth).HandleAsync(_item); await new BlazorAdmin.Services.CatalogItemServices.Edit(Auth).HandleAsync(_item);
Close(); Close();
} }

9
src/BlazorAdmin/Pages/CatalogItemPage/List.razor

@ -1,7 +1,6 @@
@page "/admin" @page "/admin"
@attribute [Authorize(Roles = Constants.Roles.ADMINISTRATORS)] @attribute [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS)]
@inject AuthService Auth @inject AuthService Auth
@using global::Shared.Authorization
@inherits BlazorAdmin.Helpers.BlazorComponent @inherits BlazorAdmin.Helpers.BlazorComponent
@namespace BlazorAdmin.Pages.CatalogItemPage @namespace BlazorAdmin.Pages.CatalogItemPage
@ -38,10 +37,10 @@ else
{ {
<tr @onclick="@(() => DetailsClick(item.Id))"> <tr @onclick="@(() => DetailsClick(item.Id))">
<td> <td>
<img class="img-thumbnail" src="@($"https://localhost:44315/{item.PictureUri}")"> <img class="img-thumbnail" src="@($"{Auth.WebUrl}{item.PictureUri}")">
</td> </td>
<td>@Services.CatalogTypeService.List.GetTypeName(catalogTypes, item.CatalogTypeId)</td> <td>@Services.CatalogTypeServices.List.GetTypeName(catalogTypes, item.CatalogTypeId)</td>
<td>@Services.CatalogBrandService.List.GetBrandName(catalogBrands, item.CatalogBrandId)</td> <td>@Services.CatalogBrandServices.List.GetBrandName(catalogBrands, item.CatalogBrandId)</td>
<td>@item.Id</td> <td>@item.Id</td>
<td>@item.Name</td> <td>@item.Name</td>
<td>@item.Description</td> <td>@item.Description</td>

14
src/BlazorAdmin/Pages/CatalogItemPage/List.razor.cs

@ -1,7 +1,7 @@
using BlazorAdmin.Helpers; using BlazorAdmin.Helpers;
using BlazorAdmin.Services.CatalogBrandService; using BlazorAdmin.Services.CatalogBrandServices;
using BlazorAdmin.Services.CatalogItemService; using BlazorAdmin.Services.CatalogItemServices;
using BlazorAdmin.Services.CatalogTypeService; using BlazorAdmin.Services.CatalogTypeServices;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,9 +22,9 @@ namespace BlazorAdmin.Pages.CatalogItemPage
{ {
if (firstRender) if (firstRender)
{ {
catalogItems = await new BlazorAdmin.Services.CatalogItemService.ListPaged(Auth).HandleAsync(50); catalogItems = await new BlazorAdmin.Services.CatalogItemServices.ListPaged(Auth).HandleAsync(50);
catalogTypes = await new BlazorAdmin.Services.CatalogTypeService.List(Auth).HandleAsync(); catalogTypes = await new BlazorAdmin.Services.CatalogTypeServices.List(Auth).HandleAsync();
catalogBrands = await new BlazorAdmin.Services.CatalogBrandService.List(Auth).HandleAsync(); catalogBrands = await new BlazorAdmin.Services.CatalogBrandServices.List(Auth).HandleAsync();
CallRequestRefresh(); CallRequestRefresh();
} }
@ -54,7 +54,7 @@ namespace BlazorAdmin.Pages.CatalogItemPage
private async Task ReloadCatalogItems() private async Task ReloadCatalogItems()
{ {
catalogItems = await new BlazorAdmin.Services.CatalogItemService.ListPaged(Auth).HandleAsync(50); catalogItems = await new BlazorAdmin.Services.CatalogItemServices.ListPaged(Auth).HandleAsync(50);
StateHasChanged(); StateHasChanged();
} }
} }

185
src/BlazorAdmin/Services/AuthService.cs

@ -1,17 +1,13 @@
using System; using System.Net.Http;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BlazorAdmin.JavaScript; using BlazorAdmin.JavaScript;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Newtonsoft.Json; using Newtonsoft.Json;
using Shared.Authorization; using BlazorShared.Authorization;
namespace BlazorAdmin.Services namespace BlazorAdmin.Services
{ {
@ -20,6 +16,12 @@ namespace BlazorAdmin.Services
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly ILocalStorageService _localStorage; private readonly ILocalStorageService _localStorage;
private readonly IJSRuntime _jSRuntime; private readonly IJSRuntime _jSRuntime;
public string ApiUrl => Constants.GetApiUrl(InDocker);
public string WebUrl => Constants.GetWebUrl(InDocker);
private static bool InDocker { get; set; }
public bool IsLoggedIn { get; set; } public bool IsLoggedIn { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
@ -30,51 +32,33 @@ namespace BlazorAdmin.Services
_jSRuntime = jSRuntime; _jSRuntime = jSRuntime;
} }
public HttpClient GetHttpClient() public async Task<HttpResponseMessage> HttpGet(string uri)
{ {
return _httpClient; return await _httpClient.GetAsync($"{ApiUrl}{uri}");
} }
public async Task<AuthResponse> LoginWithoutSaveToLocalStorage(AuthRequest user) public async Task<HttpResponseMessage> HttpDelete(string uri, int id)
{ {
var jsonContent = new StringContent(JsonConvert.SerializeObject(user), Encoding.UTF8, "application/json"); return await _httpClient.DeleteAsync($"{ApiUrl}{uri}/{id}");
var response = await _httpClient.PostAsync($"{Constants.API_URL}authenticate", jsonContent); }
var authResponse = new AuthResponse();
if (response.IsSuccessStatusCode) public async Task<HttpResponseMessage> HttpPost(string uri, object dataToSend)
{ {
authResponse = await DeserializeToAuthResponse(response); var content = ToJson(dataToSend);
IsLoggedIn = true; return await _httpClient.PostAsync($"{ApiUrl}{uri}", content);
} }
return authResponse; public async Task<HttpResponseMessage> HttpPut(string uri, object dataToSend)
}
public async Task<AuthResponse> Login(AuthRequest user)
{ {
var jsonContent = new StringContent(JsonConvert.SerializeObject(user), Encoding.UTF8, "application/json"); var content = ToJson(dataToSend);
var response = await _httpClient.PostAsync($"{Constants.API_URL}authenticate", jsonContent);
var authResponse = new AuthResponse();
if (response.IsSuccessStatusCode) return await _httpClient.PutAsync($"{ApiUrl}{uri}", content);
{
authResponse = await DeserializeToAuthResponse(response);
await SaveTokenInLocalStorage(authResponse);
await SaveUsernameInLocalStorage(authResponse);
await SetAuthorizationHeader();
UserName = await GetUsername();
IsLoggedIn = true;
}
return authResponse;
} }
public async Task Logout() public async Task Logout()
{ {
await _localStorage.RemoveItemAsync("authToken"); await DeleteLocalStorage();
await _localStorage.RemoveItemAsync("username");
await DeleteCookies(); await DeleteCookies();
RemoveAuthorizationHeader(); RemoveAuthorizationHeader();
UserName = null; UserName = null;
@ -95,44 +79,65 @@ namespace BlazorAdmin.Services
var username = await new Cookies(_jSRuntime).GetCookie("username"); var username = await new Cookies(_jSRuntime).GetCookie("username");
await SaveUsernameInLocalStorage(username); await SaveUsernameInLocalStorage(username);
var inDocker = await new Cookies(_jSRuntime).GetCookie("inDocker");
await SaveInDockerInLocalStorage(inDocker);
await RefreshLoginInfo(); await RefreshLoginInfo();
} }
private async Task LogoutIdentityManager()
public async Task<string> GetToken()
{ {
await _httpClient.PostAsync("Identity/Account/Logout", null);
var token = await _localStorage.GetItemAsync<string>("authToken");
return token;
} }
private async Task DeleteCookies() public async Task<UserInfo> GetTokenFromController()
{ {
await new Cookies(_jSRuntime).DeleteCookie("token"); return await _httpClient.GetFromJsonAsync<UserInfo>("User");
await new Cookies(_jSRuntime).DeleteCookie("username");
} }
private async Task SetLoginData() public async Task<string> GetUsername()
{ {
IsLoggedIn = !string.IsNullOrEmpty(await GetToken()); var username = await _localStorage.GetItemAsync<string>("username");
UserName = await GetUsername(); return username;
await SetAuthorizationHeader();
} }
private async Task<AuthResponse> DeserializeToAuthResponse(HttpResponseMessage response) public async Task<bool> GetInDocker()
{ {
var responseContent = await response.Content.ReadAsStringAsync(); return (await _localStorage.GetItemAsync<string>("inDocker")).ToLower() == "true";
return JsonConvert.DeserializeObject<AuthResponse>(responseContent);
} }
private async Task SaveTokenInLocalStorage(AuthResponse authResponse) private StringContent ToJson(object obj)
{ {
await _localStorage.SetItemAsync("authToken", SaveTokenInLocalStorage(authResponse.Token)); return new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
} }
private async Task SaveTokenInLocalStorage(string token) private async Task LogoutIdentityManager()
{ {
if (string.IsNullOrEmpty(token)) await _httpClient.PostAsync("Identity/Account/Logout", null);
}
private async Task DeleteLocalStorage()
{ {
return; await _localStorage.RemoveItemAsync("authToken");
await _localStorage.RemoveItemAsync("username");
await _localStorage.RemoveItemAsync("inDocker");
} }
await _localStorage.SetItemAsync("authToken", token);
private async Task DeleteCookies()
{
await new Cookies(_jSRuntime).DeleteCookie("token");
await new Cookies(_jSRuntime).DeleteCookie("username");
await new Cookies(_jSRuntime).DeleteCookie("inDocker");
}
private async Task SetLoginData()
{
IsLoggedIn = !string.IsNullOrEmpty(await GetToken());
UserName = await GetUsername();
InDocker = await GetInDocker();
await SetAuthorizationHeader();
} }
private void RemoveAuthorizationHeader() private void RemoveAuthorizationHeader()
@ -143,9 +148,13 @@ namespace BlazorAdmin.Services
} }
} }
private async Task SaveUsernameInLocalStorage(AuthResponse authResponse) private async Task SaveTokenInLocalStorage(string token)
{ {
await _localStorage.SetItemAsync("username", SaveUsernameInLocalStorage(authResponse.Username)); if (string.IsNullOrEmpty(token))
{
return;
}
await _localStorage.SetItemAsync("authToken", token);
} }
private async Task SaveUsernameInLocalStorage(string username) private async Task SaveUsernameInLocalStorage(string username)
@ -157,22 +166,13 @@ namespace BlazorAdmin.Services
await _localStorage.SetItemAsync("username", username); await _localStorage.SetItemAsync("username", username);
} }
public async Task<string> GetToken() private async Task SaveInDockerInLocalStorage(string inDocker)
{ {
if (string.IsNullOrEmpty(inDocker))
var token = await _localStorage.GetItemAsync<string>("authToken");
return token;
}
public async Task<UserInfo> GetTokenFromController()
{ {
return await _httpClient.GetFromJsonAsync<UserInfo>("User"); return;
} }
await _localStorage.SetItemAsync("inDocker", inDocker);
public async Task<string> GetUsername()
{
var username = await _localStorage.GetItemAsync<string>("username");
return username;
} }
private async Task SetAuthorizationHeader() private async Task SetAuthorizationHeader()
@ -181,52 +181,5 @@ namespace BlazorAdmin.Services
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
} }
public IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var claims = new List<Claim>();
if (string.IsNullOrEmpty(jwt))
{
return claims;
}
var payload = jwt.Split('.')[1];
var jsonBytes = ParseBase64WithoutPadding(payload);
var keyValuePairs = JsonConvert.DeserializeObject<Dictionary<string, object>>(Encoding.UTF8.GetString(jsonBytes));
keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
if (roles != null)
{
if (roles.ToString().Trim().StartsWith("["))
{
var parsedRoles = JsonConvert.DeserializeObject<string[]>(roles.ToString());
foreach (var parsedRole in parsedRoles)
{
claims.Add(new Claim(ClaimTypes.Role, parsedRole));
}
}
else
{
claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
}
keyValuePairs.Remove(ClaimTypes.Role);
}
claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
return claims;
}
private byte[] ParseBase64WithoutPadding(string base64)
{
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
} }
} }

2
src/BlazorAdmin/Services/CatalogBrandService/List.CatalogBrand.cs → src/BlazorAdmin/Services/CatalogBrandServices/List.CatalogBrand.cs

@ -1,4 +1,4 @@
namespace BlazorAdmin.Services.CatalogBrandService namespace BlazorAdmin.Services.CatalogBrandServices
{ {
public class CatalogBrand public class CatalogBrand
{ {

2
src/BlazorAdmin/Services/CatalogBrandService/List.CatalogBrandResult.cs → src/BlazorAdmin/Services/CatalogBrandServices/List.CatalogBrandResult.cs

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace BlazorAdmin.Services.CatalogBrandService namespace BlazorAdmin.Services.CatalogBrandServices
{ {
public class CatalogBrandResult public class CatalogBrandResult
{ {

4
src/BlazorAdmin/Services/CatalogBrandService/List.cs → src/BlazorAdmin/Services/CatalogBrandServices/List.cs

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogBrandService namespace BlazorAdmin.Services.CatalogBrandServices
{ {
public class List public class List
{ {
@ -26,7 +26,7 @@ namespace BlazorAdmin.Services.CatalogBrandService
try try
{ {
var result = (await _authService.GetHttpClient().GetAsync($"{Constants.API_URL}catalog-brands")); var result = await _authService.HttpGet("catalog-brands");
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return brands; return brands;

2
src/BlazorAdmin/Services/CatalogItemService/CatalogItem.cs → src/BlazorAdmin/Services/CatalogItemServices/CatalogItem.cs

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class CatalogItem public class CatalogItem
{ {

2
src/BlazorAdmin/Services/CatalogItemService/Create.CreateCatalogItemRequest.cs → src/BlazorAdmin/Services/CatalogItemServices/Create.CreateCatalogItemRequest.cs

@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class CreateCatalogItemRequest public class CreateCatalogItemRequest
{ {

2
src/BlazorAdmin/Services/CatalogItemService/Create.CreateCatalogItemResult.cs → src/BlazorAdmin/Services/CatalogItemServices/Create.CreateCatalogItemResult.cs

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class CreateCatalogItemResult public class CreateCatalogItemResult
{ {

8
src/BlazorAdmin/Services/CatalogItemService/Create.cs → src/BlazorAdmin/Services/CatalogItemServices/Create.cs

@ -1,10 +1,8 @@
using System.Net; using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class Create public class Create
{ {
@ -19,9 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemService
{ {
var catalogItemResult = new CatalogItem(); var catalogItemResult = new CatalogItem();
var content = new StringContent(JsonConvert.SerializeObject(catalogItem), Encoding.UTF8, "application/json"); var result = await _authService.HttpPost("catalog-items", catalogItem);
var result = await _authService.GetHttpClient().PostAsync($"{Constants.API_URL}catalog-items", content);
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return catalogItemResult; return catalogItemResult;

2
src/BlazorAdmin/Services/CatalogItemService/Delete.DeleteCatalogItemResult.cs → src/BlazorAdmin/Services/CatalogItemServices/Delete.DeleteCatalogItemResult.cs

@ -1,4 +1,4 @@
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class DeleteCatalogItemResult public class DeleteCatalogItemResult
{ {

4
src/BlazorAdmin/Services/CatalogItemService/Delete.cs → src/BlazorAdmin/Services/CatalogItemServices/Delete.cs

@ -2,7 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class Delete public class Delete
{ {
@ -17,7 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemService
{ {
var catalogItemResult = string.Empty; var catalogItemResult = string.Empty;
var result = await _authService.GetHttpClient().DeleteAsync($"{Constants.API_URL}catalog-items/{catalogItemId}"); var result = await _authService.HttpDelete("catalog-items", catalogItemId);
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return catalogItemResult; return catalogItemResult;

2
src/BlazorAdmin/Services/CatalogItemService/Edit.EditCatalogItemResult.cs → src/BlazorAdmin/Services/CatalogItemServices/Edit.EditCatalogItemResult.cs

@ -1,4 +1,4 @@
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class EditCatalogItemResult public class EditCatalogItemResult
{ {

8
src/BlazorAdmin/Services/CatalogItemService/Edit.cs → src/BlazorAdmin/Services/CatalogItemServices/Edit.cs

@ -1,10 +1,8 @@
using System.Net; using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class Edit public class Edit
{ {
@ -19,9 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemService
{ {
var catalogItemResult = new CatalogItem(); var catalogItemResult = new CatalogItem();
var content = new StringContent(JsonConvert.SerializeObject(catalogItem), Encoding.UTF8, "application/json"); var result = await _authService.HttpPut("catalog-items", catalogItem);
var result = await _authService.GetHttpClient().PutAsync($"{Constants.API_URL}catalog-items", content);
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return catalogItemResult; return catalogItemResult;

2
src/BlazorAdmin/Services/CatalogItemService/GetById.GetByIdCatalogItemResult.cs → src/BlazorAdmin/Services/CatalogItemServices/GetById.GetByIdCatalogItemResult.cs

@ -1,4 +1,4 @@
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class GetByIdCatalogItemResult public class GetByIdCatalogItemResult
{ {

4
src/BlazorAdmin/Services/CatalogItemService/GetById.cs → src/BlazorAdmin/Services/CatalogItemServices/GetById.cs

@ -2,7 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class GetById public class GetById
{ {
@ -17,7 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemService
{ {
var catalogItemResult = new CatalogItem(); var catalogItemResult = new CatalogItem();
var result = await _authService.GetHttpClient().GetAsync($"{Constants.API_URL}catalog-items/{catalogItemId}"); var result = await _authService.HttpGet($"catalog-items/{catalogItemId}");
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return catalogItemResult; return catalogItemResult;

2
src/BlazorAdmin/Services/CatalogItemService/ListPaged.PagedCatalogItemResult.cs → src/BlazorAdmin/Services/CatalogItemServices/ListPaged.PagedCatalogItemResult.cs

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class PagedCatalogItemResult public class PagedCatalogItemResult
{ {

4
src/BlazorAdmin/Services/CatalogItemService/ListPaged.cs → src/BlazorAdmin/Services/CatalogItemServices/ListPaged.cs

@ -3,7 +3,7 @@ using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogItemService namespace BlazorAdmin.Services.CatalogItemServices
{ {
public class ListPaged public class ListPaged
{ {
@ -18,7 +18,7 @@ namespace BlazorAdmin.Services.CatalogItemService
{ {
var catalogItems = new List<CatalogItem>(); var catalogItems = new List<CatalogItem>();
var result = (await _authService.GetHttpClient().GetAsync($"{Constants.API_URL}catalog-items?PageSize={pageSize}")); var result = await _authService.HttpGet($"catalog-items?PageSize={pageSize}");
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return catalogItems; return catalogItems;

2
src/BlazorAdmin/Services/CatalogTypeService/List.CatalogType.cs → src/BlazorAdmin/Services/CatalogTypeServices/List.CatalogType.cs

@ -1,4 +1,4 @@
namespace BlazorAdmin.Services.CatalogTypeService namespace BlazorAdmin.Services.CatalogTypeServices
{ {
public class CatalogType public class CatalogType
{ {

2
src/BlazorAdmin/Services/CatalogTypeService/List.CatalogTypeResult.cs → src/BlazorAdmin/Services/CatalogTypeServices/List.CatalogTypeResult.cs

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace BlazorAdmin.Services.CatalogTypeService namespace BlazorAdmin.Services.CatalogTypeServices
{ {
public class CatalogTypeResult public class CatalogTypeResult
{ {

4
src/BlazorAdmin/Services/CatalogTypeService/List.cs → src/BlazorAdmin/Services/CatalogTypeServices/List.cs

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace BlazorAdmin.Services.CatalogTypeService namespace BlazorAdmin.Services.CatalogTypeServices
{ {
public class List public class List
{ {
@ -27,7 +27,7 @@ namespace BlazorAdmin.Services.CatalogTypeService
try try
{ {
var result = (await _authService.GetHttpClient().GetAsync($"{Constants.API_URL}catalog-types")); var result = await _authService.HttpGet("catalog-types");
if (result.StatusCode != HttpStatusCode.OK) if (result.StatusCode != HttpStatusCode.OK)
{ {
return types; return types;

2
src/BlazorAdmin/Shared/MainLayout.razor

@ -3,7 +3,7 @@
@inherits BlazorAdmin.Helpers.BlazorLayoutComponent @inherits BlazorAdmin.Helpers.BlazorLayoutComponent
<AuthorizeView Roles=@Constants.Roles.ADMINISTRATORS> <AuthorizeView Roles=@BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS>
<div class="sidebar"> <div class="sidebar">
<NavMenu /> <NavMenu />
</div> </div>

6
src/BlazorAdmin/Shared/NavMenu.razor

@ -27,12 +27,6 @@
<span class="oi oi-account-logout" aria-hidden="true"></span> Logout <span class="oi oi-account-logout" aria-hidden="true"></span> Logout
</NavLink> </NavLink>
} }
else
{
<NavLink class="nav-link" href="login">
<span class="oi oi-account-login" aria-hidden="true"></span> Login
</NavLink>
}
</li> </li>
</ul> </ul>

2
src/BlazorAdmin/Shared/RedirectToLogin.razor

@ -4,6 +4,6 @@
protected override void OnInitialized() protected override void OnInitialized()
{ {
Navigation.NavigateTo($"Identity/Account/Login?returnUrl=" + Navigation.NavigateTo($"Identity/Account/Login?returnUrl=" +
Uri.EscapeDataString(Navigation.Uri)); $"/{Uri.EscapeDataString(Navigation.ToBaseRelativePath(Navigation.Uri))}");
} }
} }

9
src/BlazorAdmin/_Imports.razor

@ -7,11 +7,12 @@
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using Microsoft.Extensions.Logging
@using BlazorAdmin @using BlazorAdmin
@using BlazorAdmin.Shared @using BlazorAdmin.Shared
@using BlazorAdmin.Services @using BlazorAdmin.Services
@using BlazorAdmin.Services.CatalogBrandService @using BlazorAdmin.Services.CatalogBrandServices
@using BlazorAdmin.Services.CatalogItemService @using BlazorAdmin.Services.CatalogItemServices
@using BlazorAdmin.Services.CatalogTypeService @using BlazorAdmin.Services.CatalogTypeServices
@using Microsoft.Extensions.Logging
@using BlazorAdmin.JavaScript @using BlazorAdmin.JavaScript
@using BlazorShared.Authorization

5
src/BlazorAdmin/wwwroot/css/admin.css

@ -145,6 +145,11 @@ admin {
height: auto; height: auto;
} }
.esh-picture {
height: 100%;
width: 100%;
}
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.main .top-row:not(.auth) { .main .top-row:not(.auth) {
display: none; display: none;

2
src/Shared/Authorization/ClaimValue.cs → src/BlazorShared/Authorization/ClaimValue.cs

@ -1,4 +1,4 @@
namespace Shared.Authorization namespace BlazorShared.Authorization
{ {
public class ClaimValue public class ClaimValue
{ {

25
src/BlazorShared/Authorization/Constants.cs

@ -0,0 +1,25 @@
namespace BlazorShared.Authorization
{
public static class Constants
{
public static class Roles
{
public const string ADMINISTRATORS = "Administrators";
}
public static string GetApiUrl(bool inDocker) =>
inDocker ? DOCKER_API_URL : API_URL;
public static string GetWebUrl(bool inDocker) =>
inDocker ? DOCKER_WEB_URL : WEB_URL;
public static string GetOriginWebUrl(bool inDocker) =>
GetWebUrl(inDocker).TrimEnd('/');
private const string API_URL = "https://localhost:5099/api/";
private const string DOCKER_API_URL = "http://localhost:5200/api/";
private const string WEB_URL = "https://localhost:44315/";
private const string DOCKER_WEB_URL = "http://localhost:5106/";
}
}

2
src/Shared/Authorization/UserInfo.cs → src/BlazorShared/Authorization/UserInfo.cs

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Shared.Authorization namespace BlazorShared.Authorization
{ {
public class UserInfo public class UserInfo
{ {

9
src/BlazorShared/BlazorShared.csproj

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>BlazorShared</RootNamespace>
<AssemblyName>BlazorShared</AssemblyName>
</PropertyGroup>
</Project>

4
src/Infrastructure/Identity/AppIdentityDbContextSeed.cs

@ -8,7 +8,7 @@ namespace Microsoft.eShopWeb.Infrastructure.Identity
{ {
public static async Task SeedAsync(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager) public static async Task SeedAsync(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
{ {
await roleManager.CreateAsync(new IdentityRole(AuthorizationConstants.Roles.ADMINISTRATORS)); await roleManager.CreateAsync(new IdentityRole(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS));
var defaultUser = new ApplicationUser { UserName = "demouser@microsoft.com", Email = "demouser@microsoft.com" }; var defaultUser = new ApplicationUser { UserName = "demouser@microsoft.com", Email = "demouser@microsoft.com" };
await userManager.CreateAsync(defaultUser, AuthorizationConstants.DEFAULT_PASSWORD); await userManager.CreateAsync(defaultUser, AuthorizationConstants.DEFAULT_PASSWORD);
@ -17,7 +17,7 @@ namespace Microsoft.eShopWeb.Infrastructure.Identity
var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName }; var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName };
await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD); await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD);
adminUser = await userManager.FindByNameAsync(adminUserName); adminUser = await userManager.FindByNameAsync(adminUserName);
await userManager.AddToRoleAsync(adminUser, AuthorizationConstants.Roles.ADMINISTRATORS); await userManager.AddToRoleAsync(adminUser, BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
} }
} }
} }

2
src/PublicApi/CatalogItemEndpoints/Create.cs

@ -11,7 +11,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints
{ {
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class Create : BaseAsyncEndpoint<CreateCatalogItemRequest, CreateCatalogItemResponse> public class Create : BaseAsyncEndpoint<CreateCatalogItemRequest, CreateCatalogItemResponse>
{ {
private readonly IAsyncRepository<CatalogItem> _itemRepository; private readonly IAsyncRepository<CatalogItem> _itemRepository;

2
src/PublicApi/CatalogItemEndpoints/Delete.cs

@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints
{ {
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class Delete : BaseAsyncEndpoint<DeleteCatalogItemRequest, DeleteCatalogItemResponse> public class Delete : BaseAsyncEndpoint<DeleteCatalogItemRequest, DeleteCatalogItemResponse>
{ {
private readonly IAsyncRepository<CatalogItem> _itemRepository; private readonly IAsyncRepository<CatalogItem> _itemRepository;

2
src/PublicApi/CatalogItemEndpoints/Update.cs

@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints
{ {
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class Update : BaseAsyncEndpoint<UpdateCatalogItemRequest, UpdateCatalogItemResponse> public class Update : BaseAsyncEndpoint<UpdateCatalogItemRequest, UpdateCatalogItemResponse>
{ {
private readonly IAsyncRepository<CatalogItem> _itemRepository; private readonly IAsyncRepository<CatalogItem> _itemRepository;

6
src/PublicApi/Startup.cs

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using AutoMapper; using AutoMapper;
using BlazorShared.Authorization;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -25,6 +26,8 @@ namespace Microsoft.eShopWeb.PublicApi
public class Startup public class Startup
{ {
private const string CORS_POLICY = "CorsPolicy"; private const string CORS_POLICY = "CorsPolicy";
public static bool InDocker => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration)
{ {
Configuration = configuration; Configuration = configuration;
@ -114,8 +117,7 @@ namespace Microsoft.eShopWeb.PublicApi
{ {
builder.WithOrigins("http://localhost:44319", builder.WithOrigins("http://localhost:44319",
"https://localhost:44319", "https://localhost:44319",
"http://localhost:44315", Constants.GetOriginWebUrl(InDocker));
"https://localhost:44315");
builder.AllowAnyMethod(); builder.AllowAnyMethod();
builder.AllowAnyHeader(); builder.AllowAnyHeader();
}); });

7
src/Shared/Shared.csproj

@ -1,7 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

5
src/Web/Areas/Identity/Pages/Account/Login.cshtml.cs

@ -89,7 +89,7 @@ namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
if (result.Succeeded) if (result.Succeeded)
{ {
var token = await _tokenClaimsService.GetTokenAsync(Input.Email); var token = await _tokenClaimsService.GetTokenAsync(Input.Email);
CreateAuthCookie(Input.Email, token); CreateAuthCookie(Input.Email, token, Startup.InDocker);
_logger.LogInformation("User logged in."); _logger.LogInformation("User logged in.");
await TransferAnonymousBasketToUserAsync(Input.Email); await TransferAnonymousBasketToUserAsync(Input.Email);
return LocalRedirect(returnUrl); return LocalRedirect(returnUrl);
@ -114,12 +114,13 @@ namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
return Page(); return Page();
} }
private void CreateAuthCookie(string username, string token) private void CreateAuthCookie(string username, string token, bool inDocker)
{ {
var cookieOptions = new CookieOptions(); var cookieOptions = new CookieOptions();
cookieOptions.Expires = DateTime.Today.AddYears(10); cookieOptions.Expires = DateTime.Today.AddYears(10);
Response.Cookies.Append("token", token, cookieOptions); Response.Cookies.Append("token", token, cookieOptions);
Response.Cookies.Append("username", username, cookieOptions); Response.Cookies.Append("username", username, cookieOptions);
Response.Cookies.Append("inDocker", inDocker.ToString(), cookieOptions);
} }
private async Task TransferAnonymousBasketToUserAsync(string userName) private async Task TransferAnonymousBasketToUserAsync(string userName)

6
src/Web/Configuration/ConfigureCookieSettings.cs

@ -7,14 +7,14 @@ namespace Microsoft.eShopWeb.Web.Configuration
{ {
public static class ConfigureCookieSettings public static class ConfigureCookieSettings
{ {
public static void Configure(IServiceCollection services) public static IServiceCollection AddCookieSettings(this IServiceCollection services)
{ {
services.Configure<CookiePolicyOptions>(options => services.Configure<CookiePolicyOptions>(options =>
{ {
// This lambda determines whether user consent for non-essential cookies is needed for a given request. // This lambda determines whether user consent for non-essential cookies is needed for a given request.
//TODO need to check that. //TODO need to check that.
//options.CheckConsentNeeded = context => true; //options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None; options.MinimumSameSitePolicy = SameSiteMode.Strict;
}); });
services.ConfigureApplicationCookie(options => services.ConfigureApplicationCookie(options =>
{ {
@ -27,6 +27,8 @@ namespace Microsoft.eShopWeb.Web.Configuration
IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy
}; };
}); });
return services;
} }
} }
} }

4
src/Web/Configuration/ConfigureCoreServices.cs

@ -10,7 +10,7 @@ namespace Microsoft.eShopWeb.Web.Configuration
{ {
public static class ConfigureCoreServices public static class ConfigureCoreServices
{ {
public static void Configure(IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCoreServices(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
services.AddScoped<IBasketService, BasketService>(); services.AddScoped<IBasketService, BasketService>();
@ -19,6 +19,8 @@ namespace Microsoft.eShopWeb.Web.Configuration
services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>())); services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>()));
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
services.AddTransient<IEmailSender, EmailSender>(); services.AddTransient<IEmailSender, EmailSender>();
return services;
} }
} }
} }

4
src/Web/Configuration/ConfigureWebServices.cs

@ -8,7 +8,7 @@ namespace Microsoft.eShopWeb.Web.Configuration
{ {
public static class ConfigureWebServices public static class ConfigureWebServices
{ {
public static void Configure(IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddWebServices(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddMediatR(typeof(BasketViewModelService).Assembly); services.AddMediatR(typeof(BasketViewModelService).Assembly);
services.AddScoped<IBasketViewModelService, BasketViewModelService>(); services.AddScoped<IBasketViewModelService, BasketViewModelService>();
@ -16,6 +16,8 @@ namespace Microsoft.eShopWeb.Web.Configuration
services.AddScoped<ICatalogItemViewModelService, CatalogItemViewModelService>(); services.AddScoped<ICatalogItemViewModelService, CatalogItemViewModelService>();
services.Configure<CatalogSettings>(configuration); services.Configure<CatalogSettings>(configuration);
services.AddScoped<ICatalogViewModelService, CachedCatalogViewModelService>(); services.AddScoped<ICatalogViewModelService, CachedCatalogViewModelService>();
return services;
} }
} }
} }

2
src/Web/Controllers/UserController.cs

@ -3,7 +3,7 @@ using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Shared.Authorization; using BlazorShared.Authorization;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {

2
src/Web/Pages/Admin/EditCatalogItem.cshtml.cs

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Pages.Admin namespace Microsoft.eShopWeb.Web.Pages.Admin
{ {
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS)] [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS)]
public class EditCatalogItemModel : PageModel public class EditCatalogItemModel : PageModel
{ {
private readonly ICatalogItemViewModelService _catalogItemViewModelService; private readonly ICatalogItemViewModelService _catalogItemViewModelService;

2
src/Web/Pages/Admin/Index.cshtml.cs

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Pages.Admin namespace Microsoft.eShopWeb.Web.Pages.Admin
{ {
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS)] [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS)]
public class IndexModel : PageModel public class IndexModel : PageModel
{ {
public IndexModel() public IndexModel()

40
src/Web/Startup.cs

@ -15,14 +15,14 @@ using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Mime; using System.Net.Mime;
using BlazorAdmin.Services; using BlazorAdmin.Services;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Interfaces;
namespace Microsoft.eShopWeb.Web namespace Microsoft.eShopWeb.Web
@ -30,6 +30,8 @@ namespace Microsoft.eShopWeb.Web
public class Startup public class Startup
{ {
private IServiceCollection _services; private IServiceCollection _services;
public static bool InDocker => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration)
{ {
Configuration = configuration; Configuration = configuration;
@ -83,7 +85,22 @@ namespace Microsoft.eShopWeb.Web
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
ConfigureCookieSettings.Configure(services); services.AddCookieSettings();
if (InDocker)
{
services.AddDataProtection()
.SetApplicationName("eshopwebmvc")
.PersistKeysToFileSystem(new DirectoryInfo(@"./"));
}
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
});
services.AddIdentity<ApplicationUser, IdentityRole>() services.AddIdentity<ApplicationUser, IdentityRole>()
.AddDefaultUI() .AddDefaultUI()
@ -92,8 +109,8 @@ namespace Microsoft.eShopWeb.Web
services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>();
ConfigureCoreServices.Configure(services, Configuration); services.AddCoreServices(Configuration);
ConfigureWebServices.Configure(services, Configuration); services.AddWebServices(Configuration);
// Add memory cache services // Add memory cache services
services.AddMemoryCache(); services.AddMemoryCache();
@ -124,15 +141,9 @@ namespace Microsoft.eShopWeb.Web
}); });
// Blazor Admin Required Services for Prerendering // Blazor Admin Required Services for Prerendering
services.AddScoped<HttpClient>(s => services.AddScoped<HttpClient>(s => new HttpClient
{ {
var navigationManager = s.GetRequiredService<NavigationManager>(); BaseAddress = new Uri(BlazorShared.Authorization.Constants.GetWebUrl(InDocker))
return new HttpClient
{
//TODO need to do it well
BaseAddress = new Uri("https://localhost:44315/")
//BaseAddress = new Uri(navigationManager.BaseUri)
};
}); });
services.AddBlazoredLocalStorage(); services.AddBlazoredLocalStorage();
@ -197,6 +208,7 @@ namespace Microsoft.eShopWeb.Web
endpoints.MapFallbackToFile("index.html"); endpoints.MapFallbackToFile("index.html");
}); });
} }
} }
} }

2
src/Web/Web.csproj

@ -51,8 +51,8 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" /> <ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\BlazorAdmin\BlazorAdmin.csproj" /> <ProjectReference Include="..\BlazorAdmin\BlazorAdmin.csproj" />
<ProjectReference Include="..\BlazorShared\BlazorShared.csproj" />
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" /> <ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="compilerconfig.json" /> <None Include="compilerconfig.json" />

Loading…
Cancel
Save