Docker Fix (#431)

* static added to Constants

* Docker support for Blazor

* GetHttp, PostHttp, ... inside AuthService, Docker working with login, Cookies Configuration temporary disabled

* BaseAddress get web uri from Blazor Shared.

* cookie options changed to fix docker.

* Fixed returnUrl when inserting admin link and navigate without login

* Functions not used removed.

* AddPolicy using GetWebUrl

* Login link removed from NavMenu

* Change ConfigureCookieSettings, ConfigureCoreServices and ConfigureWebServices to be IServiceCollection extentions.

* GetOriginWebUrl added.

* Auto InDocker switch added.

* Removed not used using .
This commit is contained in:
Shady Nagy
2020-07-27 15:06:18 +02:00
committed by GitHub
parent e1f9ddd192
commit 688064199d
25 changed files with 172 additions and 215 deletions

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

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

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>

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>

View File

@@ -1,7 +1,6 @@
@page "/admin" @page "/admin"
@attribute [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS)] @attribute [Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS)]
@inject AuthService Auth @inject AuthService Auth
@using global::BlazorShared.Authorization
@inherits BlazorAdmin.Helpers.BlazorComponent @inherits BlazorAdmin.Helpers.BlazorComponent
@namespace BlazorAdmin.Pages.CatalogItemPage @namespace BlazorAdmin.Pages.CatalogItemPage
@@ -38,7 +37,7 @@ 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.CatalogTypeServices.List.GetTypeName(catalogTypes, item.CatalogTypeId)</td> <td>@Services.CatalogTypeServices.List.GetTypeName(catalogTypes, item.CatalogTypeId)</td>
<td>@Services.CatalogBrandServices.List.GetBrandName(catalogBrands, item.CatalogBrandId)</td> <td>@Services.CatalogBrandServices.List.GetBrandName(catalogBrands, item.CatalogBrandId)</td>

View File

@@ -1,10 +1,6 @@
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;
@@ -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

@@ -26,7 +26,7 @@ namespace BlazorAdmin.Services.CatalogBrandServices
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,4 @@
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;
@@ -19,9 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemServices
{ {
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

@@ -17,7 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemServices
{ {
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,6 +1,4 @@
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;
@@ -19,9 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemServices
{ {
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

@@ -17,7 +17,7 @@ namespace BlazorAdmin.Services.CatalogItemServices
{ {
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

@@ -18,7 +18,7 @@ namespace BlazorAdmin.Services.CatalogItemServices
{ {
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

@@ -27,7 +27,7 @@ namespace BlazorAdmin.Services.CatalogTypeServices
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

@@ -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.CatalogBrandServices @using BlazorAdmin.Services.CatalogBrandServices
@using BlazorAdmin.Services.CatalogItemServices @using BlazorAdmin.Services.CatalogItemServices
@using BlazorAdmin.Services.CatalogTypeServices @using BlazorAdmin.Services.CatalogTypeServices
@using Microsoft.Extensions.Logging
@using BlazorAdmin.JavaScript @using BlazorAdmin.JavaScript
@using BlazorShared.Authorization

View File

@@ -1,8 +1,4 @@
using System; namespace BlazorShared.Authorization
using System.Collections.Generic;
using System.Text;
namespace BlazorShared.Authorization
{ {
public class ClaimValue public class ClaimValue
{ {

View File

@@ -1,14 +1,25 @@
using System; namespace BlazorShared.Authorization
using System.Collections.Generic;
using System.Text;
namespace BlazorShared.Authorization
{ {
public class Constants public static class Constants
{ {
public static class Roles public static class Roles
{ {
public const string ADMINISTRATORS = "Administrators"; 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,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
namespace BlazorShared.Authorization namespace BlazorShared.Authorization
{ {

View File

@@ -2,9 +2,8 @@ using System;
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.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@@ -28,6 +27,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;
@@ -128,8 +129,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

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

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