Code cleanup

This commit is contained in:
Steve Smith
2020-07-28 16:12:50 -04:00
60 changed files with 273 additions and 277 deletions

View File

@@ -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).

View File

@@ -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:

View File

@@ -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}

View File

@@ -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>

View File

@@ -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";

View File

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

View File

@@ -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";
}
}
}

View File

@@ -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
{ {

View File

@@ -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);
} }
} }
} }

View File

@@ -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";
}
}

View File

@@ -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);
} }
} }
} }

View File

@@ -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();
} }

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
} }

View File

@@ -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>

View File

@@ -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();
} }
} }

View File

@@ -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)
{
authResponse = await DeserializeToAuthResponse(response);
IsLoggedIn = true;
}
return authResponse;
} }
public async Task<AuthResponse> Login(AuthRequest user) public async Task<HttpResponseMessage> HttpPost(string uri, object dataToSend)
{ {
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.PostAsync($"{ApiUrl}{uri}", content);
{ }
authResponse = await DeserializeToAuthResponse(response);
await SaveTokenInLocalStorage(authResponse);
await SaveUsernameInLocalStorage(authResponse);
await SetAuthorizationHeader();
UserName = await GetUsername(); public async Task<HttpResponseMessage> HttpPut(string uri, object dataToSend)
IsLoggedIn = true; {
} var content = ToJson(dataToSend);
return authResponse; return await _httpClient.PutAsync($"{ApiUrl}{uri}", content);
} }
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,67 +79,11 @@ 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()
{
await _httpClient.PostAsync("Identity/Account/Logout", null);
}
private async Task DeleteCookies()
{
await new Cookies(_jSRuntime).DeleteCookie("token");
await new Cookies(_jSRuntime).DeleteCookie("username");
}
private async Task SetLoginData()
{
IsLoggedIn = !string.IsNullOrEmpty(await GetToken());
UserName = await GetUsername();
await SetAuthorizationHeader();
}
private async Task<AuthResponse> DeserializeToAuthResponse(HttpResponseMessage response)
{
var responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<AuthResponse>(responseContent);
}
private async Task SaveTokenInLocalStorage(AuthResponse authResponse)
{
await _localStorage.SetItemAsync("authToken", SaveTokenInLocalStorage(authResponse.Token));
}
private async Task SaveTokenInLocalStorage(string token)
{
if (string.IsNullOrEmpty(token))
{
return;
}
await _localStorage.SetItemAsync("authToken", token);
}
private void RemoveAuthorizationHeader()
{
if (_httpClient.DefaultRequestHeaders.Contains("Authorization"))
{
_httpClient.DefaultRequestHeaders.Remove("Authorization");
}
}
private async Task SaveUsernameInLocalStorage(AuthResponse authResponse)
{
await _localStorage.SetItemAsync("username", SaveUsernameInLocalStorage(authResponse.Username));
}
private async Task SaveUsernameInLocalStorage(string username)
{
if (string.IsNullOrEmpty(username))
{
return;
}
await _localStorage.SetItemAsync("username", username);
}
public async Task<string> GetToken() public async Task<string> GetToken()
{ {
@@ -175,58 +103,83 @@ namespace BlazorAdmin.Services
return username; return username;
} }
public async Task<bool> GetInDocker()
{
return (await _localStorage.GetItemAsync<string>("inDocker")).ToLower() == "true";
}
private StringContent ToJson(object obj)
{
return new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
}
private async Task LogoutIdentityManager()
{
await _httpClient.PostAsync("Identity/Account/Logout", null);
}
private async Task DeleteLocalStorage()
{
await _localStorage.RemoveItemAsync("authToken");
await _localStorage.RemoveItemAsync("username");
await _localStorage.RemoveItemAsync("inDocker");
}
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()
{
if (_httpClient.DefaultRequestHeaders.Contains("Authorization"))
{
_httpClient.DefaultRequestHeaders.Remove("Authorization");
}
}
private async Task SaveTokenInLocalStorage(string token)
{
if (string.IsNullOrEmpty(token))
{
return;
}
await _localStorage.SetItemAsync("authToken", token);
}
private async Task SaveUsernameInLocalStorage(string username)
{
if (string.IsNullOrEmpty(username))
{
return;
}
await _localStorage.SetItemAsync("username", username);
}
private async Task SaveInDockerInLocalStorage(string inDocker)
{
if (string.IsNullOrEmpty(inDocker))
{
return;
}
await _localStorage.SetItemAsync("inDocker", inDocker);
}
private async Task SetAuthorizationHeader() private async Task SetAuthorizationHeader()
{ {
var token = await GetToken(); var token = await GetToken();
_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);
}
} }
} }

View File

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

View File

@@ -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
{ {

View File

@@ -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;

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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;

View File

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

View File

@@ -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;

View File

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

View File

@@ -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;

View File

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

View File

@@ -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;

View File

@@ -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
{ {

View File

@@ -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;

View File

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

View File

@@ -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
{ {

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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))}");
} }
} }

View File

@@ -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

View File

@@ -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;

View File

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

View File

@@ -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/";
}
}

View File

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

View File

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

View File

@@ -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);
} }
} }
} }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}); });

View File

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

View File

@@ -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)

View File

@@ -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;
} }
} }
} }

View File

@@ -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;
} }
} }
} }

View File

@@ -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;
} }
} }
} }

View File

@@ -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
{ {

View File

@@ -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;

View File

@@ -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()

View File

@@ -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");
}); });
} }
} }
} }

View File

@@ -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" />