Commit 4bae0771 authored by Daniel Roth's avatar Daniel Roth
Browse files

Update 02-customize-a-pizza

parent b8e84c42
......@@ -186,7 +186,7 @@ The user should also be able to select additional toppings on `ConfigurePizzaDia
protected async override Task OnInitializedAsync()
{
toppings = await HttpClient.GetJsonAsync<List<Topping>>("toppings");
toppings = await HttpClient.GetFromJsonAsync<List<Topping>>("toppings");
}
}
```
......@@ -402,7 +402,7 @@ void RemoveConfiguredPizza(Pizza pizza)
async Task PlaceOrder()
{
await HttpClient.PostJsonAsync("orders", order);
await HttpClient.PostAsJsonAsync("orders", order);
order = new Order();
}
```
......
......@@ -4,7 +4,7 @@
</Found>
<NotFound>
<LayoutView Layout="typeof(MainLayout)">
<div class="main">Page not found</div>
<div class="main">Sorry, there's nothing at this address.</div>
</LayoutView>
</NotFound>
</Router>
......@@ -9,8 +9,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="$(BlazorVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="$(BlazorVersion)" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="$(BlazorVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.Net.Http.Json" Version="$(SystemNetHttpJsonVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="$(BlazorVersion)" />
</ItemGroup>
<ItemGroup>
......
......@@ -61,7 +61,7 @@
protected override async Task OnInitializedAsync()
{
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("specials");
specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>("specials");
}
void ShowConfigurePizzaDialog(PizzaSpecial special)
......@@ -98,7 +98,7 @@
async Task PlaceOrder()
{
await HttpClient.PostJsonAsync("orders", order);
await HttpClient.PostAsJsonAsync("orders", order);
order = new Order();
}
}
......@@ -69,7 +69,7 @@
protected async override Task OnInitializedAsync()
{
toppings = await HttpClient.GetJsonAsync<List<Topping>>("toppings");
toppings = await HttpClient.GetFromJsonAsync<List<Topping>>("toppings");
}
void ToppingSelected(ChangeEventArgs e)
......
@inherits LayoutComponentBase
<div class="top-bar">
<img class="logo" src="img/logo.svg" />
<a class="logo" href="">
<img src="img/logo.svg" />
</a>
<NavLink href="" class="nav-tab" Match="NavLinkMatch.All">
<img src="img/pizza-slice.svg" />
......
@using System.Net.Http
@using System.Net.Http.Headers
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.JSInterop
@using BlazingPizza.Client
@using BlazingPizza.Client.Shared
......
......@@ -36,10 +36,14 @@ form {
}
.logo {
margin-right: 3rem;
width: 9rem;
display: flex;
}
.logo > img {
margin-right: 3rem;
width: 9rem;
}
.content {
display: flex;
height: 100%;
......@@ -120,6 +124,8 @@ form {
font-weight: 700;
line-height: 0.7rem;
margin-top: 0.5rem;
color: white;
font-size: 1rem;
}
.user-info a {
......@@ -127,6 +133,12 @@ form {
font-size: 0.8rem;
}
.user-info button.sign-out {
color: #fff2cc;
font-size: 0.8rem;
padding: 0;
}
.pizza-cards {
display: grid;
grid-template-columns: repeat(auto-fill, 20rem);
......@@ -540,6 +552,7 @@ a.sign-in {
font-weight: 100;
cursor: pointer;
transition: 0.2s ease-out;
margin-left: 3px;
}
a.sign-in:hover {
......@@ -548,16 +561,6 @@ a.sign-in {
border-color: #fff2cc;
}
.user-info a.sign-out {
color: #fff2cc;
font-size: 0.8rem;
cursor: pointer;
}
.user-info a.sign-out:hover {
text-decoration: underline;
}
input[type=range] {
-webkit-appearance: none;
margin: 7.1px 0;
......@@ -721,6 +724,25 @@ input[type=range] {
color: red;
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
@keyframes progressbar-slide {
0% {
transform: translateX(-200px);
......@@ -733,4 +755,4 @@ input[type=range] {
100% {
transform: translateX(500px);
}
}
}
\ No newline at end of file
......@@ -15,6 +15,12 @@
<div class="loading-bar"></div>
</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/BlazingPizza.ComponentsLibrary/localStorage.js"></script>
<script src="_content/BlazingPizza.ComponentsLibrary/pushNotifications.js"></script>
......
@using Microsoft.AspNetCore.Identity
@using BlazingPizza.Server
@inject SignInManager<PizzaStoreUser> SignInManager
@inject UserManager<PizzaStoreUser> UserManager
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
var returnUrl = "/";
if (Context.Request.Query.TryGetValue("returnUrl", out var existingUrl))
{
returnUrl = existingUrl;
}
}
<div class="user-info">
@if (SignInManager.IsSignedIn(User))
{
<img src="~/img/user.svg" />
<div>
<a class="username" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">@User.Identity.Name</a>
<form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="/" method="post">
<button type="submit" class="btn btn-link sign-out">Sign out</button>
</form>
</div>
}
else
{
<a class="sign-in" asp-area="Identity" asp-page="/Account/Register" asp-route-returnUrl="@returnUrl">Register</a>
<a class="sign-in" asp-area="Identity" asp-page="/Account/Login" asp-route-returnUrl="@returnUrl">Login</a>
}
</div>
@using Microsoft.AspNetCore.Hosting
@using Microsoft.AspNetCore.Mvc.ViewEngines
@using BlazingPizza.Client.Shared
@inject IWebHostEnvironment Environment
@inject ICompositeViewEngine Engine
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="~/img/icon-512.png" rel="icon" />
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="~/css/site.css" rel="stylesheet" asp-append-version="true" />
<title>Blazing Pizza - @ViewData["Title"]</title>
</head>
<body>
<div class="top-bar">
<a class="logo" href="~/">
<img src="~/img/logo.svg" />
</a>
<partial name="_LoginPartial" />
</div>
<div class="content">
<div class="main">
@RenderBody()
</div>
</div>
<script src="~/Identity/lib/jquery/dist/jquery.min.js"></script>
<script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
......@@ -6,10 +6,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="$(BlazorVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(EntityFrameworkVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="$(EntityFrameworkVersion)" />
</ItemGroup>
<ItemGroup>
......
......@@ -36,7 +36,6 @@ namespace BlazingPizza.Server
private string GetUserId()
{
// This will be the user's twitter username
return HttpContext.User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name")?.Value;
}
}
......
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazingPizza.Server
{
public class OidcConfigurationController : Controller
{
public OidcConfigurationController(IClientRequestParametersProvider clientRequestParametersProvider)
{
ClientRequestParametersProvider = clientRequestParametersProvider;
}
public IClientRequestParametersProvider ClientRequestParametersProvider { get; }
[HttpGet("_configuration/{clientId}")]
public IActionResult GetClientRequestParameters([FromRoute]string clientId)
{
var parameters = ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId);
return Ok(parameters);
}
}
}
......@@ -89,7 +89,6 @@ namespace BlazingPizza.Server
private string GetUserId()
{
// This will be the user's twitter username
return HttpContext.User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name")?.Value;
}
......
using Microsoft.EntityFrameworkCore;
using IdentityServer4.EntityFramework.Options;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace BlazingPizza.Server
{
public class PizzaStoreContext : DbContext
public class PizzaStoreContext : ApiAuthorizationDbContext<PizzaStoreUser>
{
public PizzaStoreContext()
{
}
public PizzaStoreContext(DbContextOptions options)
: base(options)
public PizzaStoreContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
......@@ -25,6 +25,8 @@ namespace BlazingPizza.Server
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configuring a many-to-many special -> topping relationship that is friendly for serialization
modelBuilder.Entity<PizzaTopping>().HasKey(pst => new { pst.PizzaId, pst.ToppingId });
modelBuilder.Entity<PizzaTopping>().HasOne<Pizza>().WithMany(ps => ps.Toppings);
......@@ -34,4 +36,4 @@ namespace BlazingPizza.Server
modelBuilder.Entity<Order>().OwnsOne(o => o.DeliveryLocation);
}
}
}
}
\ No newline at end of file
using Microsoft.AspNetCore.Identity;
namespace BlazingPizza.Server
{
public class PizzaStoreUser : IdentityUser
{
}
}
\ No newline at end of file
......@@ -3,14 +3,15 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:64589/",
"sslPort": 0
"applicationUrl": "http://localhost:64588/",
"sslPort": 44381
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
......@@ -18,10 +19,11 @@
"BlazingPizza.Server": {
"commandName": "Project",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:64590/"
}
}
}
}
\ No newline at end of file
using System.Linq;
using System.Net.Mime;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
......@@ -26,36 +22,21 @@ namespace BlazingPizza.Server
services.AddMvc()
.AddNewtonsoftJson();
services.AddDbContext<PizzaStoreContext>(options => options.UseSqlite("Data Source=pizza.db"));
services.AddDbContext<PizzaStoreContext>(options =>
options.UseSqlite("Data Source=pizza.db"));
services.AddResponseCompression(options =>
{
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { MediaTypeNames.Application.Octet });
});
services.AddDefaultIdentity<PizzaStoreUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<PizzaStoreContext>();
services
.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddTwitter(twitterOptions =>
{
twitterOptions.ConsumerKey = Configuration["Authentication:Twitter:ConsumerKey"];
twitterOptions.ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"];
twitterOptions.Events.OnRemoteFailure = (context) =>
{
context.HandleResponse();
return context.Response.WriteAsync("<script>window.close();</script>");
};
});
services.AddIdentityServer()
.AddApiAuthorization<PizzaStoreUser, PizzaStoreContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
......@@ -75,13 +56,15 @@ namespace BlazingPizza.Server
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
endpoints.MapFallbackToFile("index.html");
});
}
}
}
}
\ No newline at end of file
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace BlazingPizza.Server
{
[ApiController]
public class UserController : Controller
{
private static UserInfo LoggedOutUser = new UserInfo { IsAuthenticated = false };
[HttpGet("user")]
public UserInfo GetUser()
{
return User.Identity.IsAuthenticated
? new UserInfo { Name = User.Identity.Name, IsAuthenticated = true }
: LoggedOutUser;
}
[HttpGet("user/signin")]
public async Task SignIn(string redirectUri)
{
if (string.IsNullOrEmpty(redirectUri) || !Url.IsLocalUrl(redirectUri))
{
redirectUri = "/";
}
await HttpContext.ChallengeAsync(
TwitterDefaults.AuthenticationScheme,
new AuthenticationProperties { RedirectUri = redirectUri });
}
[HttpGet("user/signout")]
public async Task<IActionResult> SignOut()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Redirect("~/");
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment