How do I add a Blazor WebAssembly project to an existing ASP.NET Core application?
Follow these steps to add a Blazor WebAssembly project to an existing ASP.NET Core application: Create a ASP.NET Core application and Blazor WebAssembly application separately. Install the Microsoft.AspNetCore.Components.WebAssembly.Server NuGet package in the ASP.NET Core application and add the Blazor WebAssembly application project reference to the ASP.NET Core application.[AspNetCoreApp.csproj] <Project Sdk=”Microsoft.NET.Sdk.Web”> <ItemGroup> <PackageReference Include=”Microsoft.AspNetCore.Components.WebAssembly.Server” Version=”7.0.0″ /> </ItemGroup> <ItemGroup> <ProjectReference Include=”..{Your Blazor App Path}” /> </ItemGroup> </Project> Add the following configurations the Program.cs file in the ASP.NET Core app to include Blazor WebAssembly.[Program.cs] ….if (!app.Environment.IsDevelopment()){ app.UseWebAssemblyDebugging(); app.UseExceptionHandler(“/Error”); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts();} app.UseBlazorFrameworkFiles(); app.MapFallbackToFile(“index.html”); //app.MapRazorPages(); // Remove this line. app.Run(); To avoid conflicts during publishing between WebAssembly and ASP.NET Core applications, it is necessary to delete the favicon.ico file. By default, both projects create a favicon.ico file, which can lead to conflicts. To resolve this, remove one of the favicon.ico files from the project. Refer to this link for more information. View Sample in GitHub
How do I add authentication to a Blazor WebAssembly app?
Blazor authentication is implemented to determine who a particular user is. Blazor follows the existing ASP.NET Core authentication mechanisms to show a user’s identity.Follow these steps to implement authentication within Blazor WebAssembly: Create a Blazor WebAssembly app with individual user account authentication in Visual Studio 2019. Install the NuGet package named “Microsoft.AspNetCore.Components.WebAssembly.Authentication” using the NuGet package manager. To support the authenticating service, add the AddOidcAuthentication service configuration to the Program.cs file.[Program.cs] using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;. . . builder.Services.AddOidcAuthentication(options => { builder.Configuration.Bind(“Auth0”, options.ProviderOptions); options.ProviderOptions.ResponseType = “code”; }); In wwwroot/appsettings.json file, replace the Authority and Client ID placeholders with the proper values taken from the Auth0 dashboard.Note: Use Auth0; it will let you integrate authentication for configuring your application. Refer to this link for how to configure the application.[wwwroot/appsetting.json] { “Auth0”: { “Authority”: “https://<YOUR_AUTH0_DOMAIN>”, “ClientId”: “<YOUR_CLIENT_ID>” }} Add the authentication service script reference to the index.html file, which handles the low-level details of the OIDC protocol.[index.html] <body> //. . . <script src=”_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js”> </script> </body> Add CascadingAuthenticationState and AuthorizeRouteView to display the page matching the specified route only if the user is authorized. Otherwise, it redirects to the Login page.[App.razor] <CascadingAuthenticationState> <Router AppAssembly=”@typeof(Program).Assembly”> <Found Context=”routeData”> <AuthorizeRouteView RouteData=”@routeData” DefaultLayout=”@typeof(MainLayout)”> <Authorizing> <p>Loading…</p> </Authorizing> <NotAuthorized> <p>You’re not authorized to reach this page. You need to log in.</p> </NotAuthorized> </AuthorizeRouteView> </Found> <NotFound> <p>Sorry, there’s nothing at this address.</p> </NotFound> </Router> </CascadingAuthenticationState> Create a Razor component to allow the user to log in to be authenticated in the Shared folder.[Shared/LoginControl.razor] @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @inject NavigationManager UriHelper @inject SignOutSessionStateManager SignOutManager <AuthorizeView> <Authorized> Hello, @context.User.Identity.Name! <a href=”#” @onclick=”OnClickEvent”>Log out</a> </Authorized> <NotAuthorized> <a href=”authentication/login”>Log in</a> </NotAuthorized> </AuthorizeView> @code{ private async Task OnClickEvent(MouseEventArgs args) { await SignOutManager.SetSignOutState(); UriHelper.NavigateTo(“authentication/logout”); } } Reference the LoginControl page in the MainLayout.razor page.[MainLayout.razor] <div class=”main”> <div class=”top-row px-4 auth”> <LoginControl /> <a href=”https://docs.microsoft.com/aspnet/” target=”_blank”>About</a> </div> <div class=”content px-4″> @Body </div> </div> Create an Authentication.razor component in the Pages folder to authenticate the user when logging in and out of the app.[Pages/Authentication.razor] @page “/authentication/{action}”@using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using Microsoft.Extensions.Configuration @inject NavigationManager UriHelper @inject IConfiguration Config <RemoteAuthenticatorView Action=”@Action”> <LogOut> @{ var authority = (string)Config[“Auth0:Authority”]; var clientId = (string)Config[“Auth0:ClientId”]; UriHelper.NavigateTo($”{authority}/v2/logout?client_id={clientId}”); } </LogOut> </RemoteAuthenticatorView> @code{ [Parameter] public string Action { get; set; } } Now display the authorized content when the app is authorized. If the app is not authorized, display the “Not Authorized” message to the user.[Index.razor] @page “/” <AuthorizeView> <Authorized> <h1>Hello, @context.User.Identity.Name !</h1> <p>Welcome to your new app.</p> </Authorized> <NotAuthorized> <p>Not Authorized</p> </NotAuthorized> </AuthorizeView> Press Ctrl + F5 to run the application and click Log in in the header to authenticate the user. Refer to this documentation for more details. View Sample in GitHub
What is JavaScript isolation in Blazor components?
Blazor allows JavaScript isolation in standard JavaScript modules. JavaScript isolation provides the following benefits: JavaScript code is allowed to load only specified components. Imported JavaScript does not affect any global namespace. Library and component consumers are not required to import the related JavaScript. Follow these steps to implement JavaScript isolation in Blazor: Create an export JavaScript function in the wwwroot/script folder.[isolationScript.js] export function jsIsolation(value) { console.log(value); } Import the JavaScript function using the IJSRuntime.InvokeAsync method in Blazor and call the JavaScript method on button click event.[Index.razor] @page “/”@inject IJSRuntime JSRuntime Enter text:<input @bind=”content” /> <button class=”btn btn-primary” @onclick=”OnClickButton”>Click</button> @code { private string content { get; set; } private async void OnClickButton() { var jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>(“import”, “./script/isolationScript.js”); await jsModule.InvokeVoidAsync(“jsIsolation”, content); } } The JavaScript code file loads only during a button click event. It will not load again and again for each button click. Refer to this documentation for more details.
How do I implement Blazor authentication with OpenID Connect?
Blazor authentication is implemented to determine who a particular user is. Blazor follows the existing ASP.NET Core authentication mechanisms to show a user’s identity.Follow these steps to implement authentication with OpenID Connect in Blazor: Create Blazor application Create a Blazor Server app and install a NuGet package named “Microsoft.AspNetCore.Authentication.OpenIdConnect” using the NuGet package manager. Add OIDC and authentication configuration Add OpenID Connect and cookie authentication service configuration to the Blazor Server app in the Startup.cs file.[Startup.cs] using Microsoft.AspNetCore.Authentication.Cookies;using Microsoft.AspNetCore.Authentication.OpenIdConnect;using Microsoft.IdentityModel.Tokens; namespace BlazorServerApp{ public class Startup { . . . . . . public void ConfigureServices(IServiceCollection services) { . . . . . . services.AddAuthentication(opt => { opt.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; opt.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }).AddCookie().AddOpenIdConnect(“oidc”, options => { options.Authority = “https://demo.identityserver.io/”; options.ClientId = “interactive.confidential.short”; options.ClientSecret = “secret”; options.ResponseType = “code”; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.UseTokenLifetime = false; options.Scope.Add(“openid”); options.Scope.Add(“profile”); options.TokenValidationParameters = new TokenValidationParameters{ NameClaimType = “name” }; options.Events = new OpenIdConnectEvents { OnAccessDenied = context => { context.HandleResponse(); context.Response.Redirect(“/”); return Task.CompletedTask; } }; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { . . . . . . app.UseAuthentication(); app.UseAuthorization(); } } } Add AuthorizeRouteView to the App.razor file Add AuthorizeRouteView to display the page matching the specified route only if the user is authorized.[App.razor] @inject NavigationManager UriHelper <CascadingAuthenticationState> <Router AppAssembly=”@typeof(Program).Assembly”> <Found Context=”routeData”> <AuthorizeRouteView RouteData=”@routeData” DefaultLayout=”@typeof(MainLayout)”> <NotAuthorized> @{ var returnUrl = UriHelper.ToBaseRelativePath(UriHelper.Uri); UriHelper.NavigateTo($”login?redirectUri={returnUrl}”, forceLoad: true); } </NotAuthorized> <Authorizing> Loading… </Authorizing> </AuthorizeRouteView> </Found> <NotFound> <LayoutView Layout=”@typeof(MainLayout)”> <p>Sorry, there’s nothing at this address.</p> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState> Add buttons Add Log out and Log in buttons to authorize the user in the header section.[MainLayout.razor] <div class=”top-row px-4″> <AuthorizeView> <Authorized> <form method=”get” action=”logout”> <button type=”submit” class=”nav-link btn btn-link”>Log out</button> </form> </Authorized> <NotAuthorized> <a href=”login?redirectUri=/”>Log in</a> </NotAuthorized> </AuthorizeView> <a href=”https://docs.microsoft.com/aspnet/” target=”_blank”>About</a> </div> Redirect requests to log in or log out users Create Razor pages for login (Login.cshtml.cs) and logout (Logout.cshtml.cs) redirection requests to IdentityServer for authorization under the Pages folder.[Login.cshtml.cs] using Microsoft.AspNetCore.Authentication; namespace BlazorServerApp.Pages{ public class LoginModel : PageModel { public async Task OnGet(string redirectUri) { await HttpContext.ChallengeAsync(“oidc”, new AuthenticationProperties { RedirectUri = redirectUri }); } } } [Logout.cshtml.cs] using Microsoft.AspNetCore.Authentication; namespace BlazorServerApp.Pages{ public class LogoutModel : PageModel { public async Task<IActionResult> OnGetAsync() { await HttpContext.SignOutAsync(); return Redirect(“/”); } } } Show authorized content in Razor component Following is the code to display the authorized content when the app is authorized. If the app is not authorized, it displays the “Not Authorized” message to the user.[Index.razor] @page “/” <AuthorizeView> <Authorized> <h1>Hello, @context.User.Identity.Name !</h1> <p>Welcome to your new app.</p> </Authorized> <NotAuthorized> <p>Not Authorized</p> </NotAuthorized> </AuthorizeView> Run the application Press Ctrl + F5 to run the application and click Log in in the header to authenticate the user. You can download the reference sample on GitHub.
How do I do cookie authentication in Blazor?
Cookies are created by the application and passed to the user’s web browser when the user submits the request. The web browser passes the cookie back to the application to indicate that the user is authenticated. When the user logs out, the cookie is removed.Follow these steps to set a cookie and read that cookie with authentication in Blazor. Configure the cookie authentication services in the Startup.cs file.[Startup.cs] public class Startup{ . . . . . . public void ConfigureServices(IServiceCollection services) { . . . . . . services.AddAuthentication(“Cookies”).AddCookie(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { . . . . . . app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); . . . . . . }); } } Now, add a controller page to set the cookie to the browser and redirect the URL.[CookieController.cs] using Microsoft.AspNetCore.Authentication;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using System.Collections.Generic;using System.Security.Claims;using System.Threading.Tasks; namespace blazorcookie { [Route(“/[controller]”)] [ApiController] public class CookieController : ControllerBase { [HttpPost] public async Task<ActionResult> Login([FromForm] string name) { ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim> { new Claim(ClaimTypes.NameIdentifier, name) }, “auth”); ClaimsPrincipal claims = new ClaimsPrincipal(claimsIdentity); await HttpContext.SignInAsync(claims); return Redirect(“/”); } } } To use the authorized view, configure the CascadingAuthenticationState component in the App.razor file. This will let you check the authentication state inside the Blazor application.[ App.razor ] <CascadingAuthenticationState> <Router AppAssembly=”@typeof(Program).Assembly” PreferExactMatches=”@true”> . . . . . . . . . </Router></CascadingAuthenticationState> Use form action to call the cookie controller to set the cookie and have it read by AuthorizeView user name.[Index.razor] @page “/” <AuthorizeView> <Authorized> <h1>Hello @context.User.Claims.First().Value</h1> </Authorized></AuthorizeView> <form action=”cookie” method=”post”> <input type=”text” name=”name” /> <input type=”submit” /></form> Run the application and submit the form request. You will find an authentication cookie with the scheme “Cookies,” which was specified in the ConfigureServices() method of the Startup class. Refer to this blog post for more details and download the sample on GitHub.