ASP.NET Core Blazor 使用者身分驗證 之 登入與登出
在這篇文章所提到的專案原始碼,可以從 GitHub 下載
使用預設專案範本建立 Blazor 專案
想要進行這樣的專案開發練習,可以參考底下的操作步驟
- 打開 Visual Studio 2019 開發工具
- 當 [Visual Studio 2019] 對話窗出現之後,點選右下方的 [建立新的專案] 按鈕
- 在 [建立新專案] 對話窗內,請找出 [Blazor 應用程式] 這個專案開發範本,並且點選這個專案開發範本
- 請點選右下角 [下一步] 按鈕
- 出現 [設定新的專案] 對話窗,輸入適當的 [專案名稱] 、 [位置] ,完成後,請點選右下角 [建立] 按鈕
🕬 說明
在這個範例程式碼中,將會建立一個 BlazorAuthentication 專案名稱# - 此時將會看到 [建立新的 Blazor 應用程式] 對話窗,這裡可以根據當時開發專案的需要,自行決定是否有調整 Blazor 專案的其他特性,若無,請點選右下角的 [建立] 按鈕
- 此時,這個 Blazor 專案已經建立完成
🔑 注意事項
在建立練習專案的時候,無須在 [建立新的 Blazor 應用程式] 對話窗下,點選該對話窗右上方的 [驗證] 設定選項,也就是,維持 [驗證] 選項為 [無驗證]#
加入本專案會用到的 NuGet 套件
- 滑鼠右擊這個專案節點
- 選擇 [管理 NuGet 套件] 選項
- 點選 [瀏覽] 標籤頁次
- 請記得在這裡一定要勾選 [包括搶鮮版] 選項
- 從清單中找到 [Microsoft.AspNetCore.Blazor.HttpClient] 項目,請點選這個項目
- 點選右上方的 [安裝] 按鈕
- 完成這個 [Microsoft.AspNetCore.Blazor.HttpClient] NuGet 套件的安裝
建立相關方案資料夾
- 滑鼠右擊這個專案節點
- 選擇 [加入] > [新增資料夾] 選項
- 使用
Controllers
名稱作為該方案資料夾的名稱
建立登入與登出的 Razor Page 頁面
建立登入 Razor Page 頁面
- 滑鼠右擊這個專案節點內的 [Pages] 資料夾
- 選擇 [加入] > [新增項目] 選項
- 在 [新增項目] 對話窗內,選擇 [Razor 頁面] 選項
- 在下方 [名稱] 欄位內,輸入
Login.cshtml
- 點選 [新增] 按鈕,完成這個登入 Razor 頁面的建立
- 打開 [Pages] 資料夾內的 [Login.cshtml] 檔案
- 使用底下 Razor 標記語法替換掉這個檔案內的內容
@page
@model BlazorAuthentication.Pages.LoginModel
@{
ViewData["Title"] = "登入";
}
<h2>登入</h2>
- 在 [Pages] 資料夾內,找到 [Login.cshtml] 節點內的 [Login.cshtml.cs]
- 使用滑鼠雙擊這個 [Login.cshtml.cs] 節點,打開這個檔案內容
- 使用底下 C# 程式碼替換掉原先這個檔案內的內容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
#region 這裡將會是新加入的命名空間宣告
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
#endregion
namespace BlazorAuthentication.Pages
{
[AllowAnonymous]
public class LoginModel : PageModel
{
public string ReturnUrl { get; set; }
public async Task<IActionResult> OnGetAsync(string paramUsername, string paramPassword)
{
string returnUrl = Url.Content("~/");
try
{
// 清除已經存在的登入 Cookie 內容
await HttpContext
.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
}
catch { }
#region 這裡將會要針對傳入的使用者帳號與密碼進行驗證
#region 本練習簡化將不做任何驗證,不過,本練習將簡化不做任何設計
#endregion
#region 加入這個使用者需要用到的 宣告類型 Claim Type
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, paramUsername),
new Claim(ClaimTypes.Role, "Administrator"),
};
#endregion
#region 建立 宣告式身分識別
// ClaimsIdentity類別是宣告式身分識別的具體執行, 也就是宣告集合所描述的身分識別
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
#endregion
#region 建立關於認證階段需要儲存的狀態
var authProperties = new AuthenticationProperties
{
IsPersistent = true,
RedirectUri = this.Request.Host.Value
};
#endregion
#region 進行使用登入
try
{
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
}
catch (Exception ex)
{
string error = ex.Message;
}
#endregion
#endregion
return LocalRedirect(returnUrl);
}
}
}
建立登出 Razor Page 頁面
- 滑鼠右擊這個專案節點內的 [Pages] 資料夾
- 選擇 [加入] > [新增項目] 選項
- 在 [新增項目] 對話窗內,選擇 [Razor 頁面] 選項
- 在下方 [名稱] 欄位內,輸入
Logout.cshtml
- 點選 [新增] 按鈕,完成這個登入 Razor 頁面的建立
- 打開 [Pages] 資料夾內的 [Logout.cshtml] 檔案
- 使用底下 Razor 標記語法替換掉這個檔案內的內容
@page
@model BlazorAuthentication.Pages.LogoutModel
@{
ViewData["Title"] = "登出";
}
<h2>登出</h2>
- 在 [Pages] 資料夾內,找到 [Logout.cshtml] 節點內的 [Logout.cshtml.cs]
- 使用滑鼠雙擊這個 [Logout.cshtml.cs] 節點,打開這個檔案內容
- 使用底下 C# 程式碼替換掉原先這個檔案內的內容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
#region 這裡將會是新加入的命名空間宣告
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
#endregion
namespace BlazorAuthentication.Pages
{
public class LogoutModel : PageModel
{
public async Task<IActionResult> OnGetAsync()
{
// 清除已經存在的登入 Cookie 內容
await HttpContext
.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
return LocalRedirect(Url.Content("~/"));
}
}
}
建立登出入使用的 Blazor Razor Component 元件
- 滑鼠右擊這個專案節點內的 [Shared] 資料夾
- 選擇 [加入] > [新增項目] 選項
- 在 [新增項目] 對話窗內,選擇 [Razor 頁面] 選項
- 在下方 [名稱] 欄位內,輸入
LoginControl.razor
- 點選 [新增] 按鈕,完成這個登入 Razor 頁面的建立
- 打開 [Shared] 資料夾內的 [LoginControl.razor] 檔案
- 使用底下 Razor 標記語法替換掉這個檔案內的內容
@page "/LoginControl"
<AuthorizeView>
<Authorized>
<b>Hello, @context.User.Identity.Name!</b>
<a class="ml-md-auto btn btn-primary"
href="/logout?returnUrl=/"
target="_top"> 登出 </a>
</Authorized>
<NotAuthorized>
<input type="text"
placeholder="User Name"
@bind="@Username" />
<input type="password"
placeholder="Password"
@bind="@Password" />
<a class="ml-md-auto btn btn-primary"
href="/login?paramUsername=@Username¶mPassword=@Password"
target="_top"> 登入 </a>
</NotAuthorized>
</AuthorizeView>
@code {
string Username = "";
string Password = "";
}
進行 ASP.NET Core 專案的啟動設定修正
- 在這個專案內找到 [Startup.cs] 檔案
- 使用滑鼠雙擊這個檔案,打開這個檔案
- 使用底下 C# 程式碼替換掉原有的檔案內容
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using BlazorAuthentication.Data;
#region 這裡將會是新加入的命名空間宣告
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using System.Net.Http;
#endregion
namespace BlazorAuthentication
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
#region 加入使用 Cookie 認證需要的宣告
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
});
services.AddAuthentication(
CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
#endregion
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
#region 加入會用到的服務宣告
services.AddHttpContextAccessor();
services.AddScoped<HttpContextAccessor>();
services.AddHttpClient();
services.AddScoped<HttpClient>();
#endregion
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
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.UseHttpsRedirection();
app.UseStaticFiles();
#region 指定要使用 Cookie & 使用者認證的中介軟體
app.UseCookiePolicy();
app.UseAuthentication();
#endregion
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
#region 這裡要加入 Web API 控制器會用到的路由
endpoints.MapControllerRoute("default", "{controller=Home}/action=Index/{id}");
#endregion
});
}
}
}
修正這個 Blazor 專案的整體路由設定
- 在該專案根目錄下,找到並且打開 [App.razor] 檔案
- 使用底下 Razor 元件 標記語法替換掉這個檔案內的內容
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
修正主要版片配置的內容
- 在該專案的 [Shared] 目錄下,找到並且打開 [MainLayout.razor] 檔案
- 使用底下 Razor 元件 標記語法替換掉這個檔案內的內容
@inherits LayoutComponentBase
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
@*在這裡加入剛剛建立的登出入 Blazor 元件*@
<LoginControl />
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<div class="content px-4">
@Body
</div>
</div>
修正該專案的首頁 Blazor 元件
- 在該專案的 [Pages] 目錄下,找到並且打開 [Index.razor] 檔案
- 使用底下 Razor 元件 標記語法替換掉這個檔案內的內容
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<AuthorizeView>
<Authorized>
<h1>你好, @context.User.Identity.Name!</h1>
<p>因為已經通過身分驗證成功,所以,會看到這個訊息</p>
</Authorized>
<NotAuthorized>
<p>你尚未通過身分驗證,所以,會看到這個訊息</p>
</NotAuthorized>
</AuthorizeView>
執行專案
- 請執行這個 Blazor 專案
- 將會看到如下圖的網頁顯示出來
- 在網頁的最上方,將會看到剛剛設計的 [LoginControl.razor] 元件
- 因為現在尚未通過身分驗證,所以,在 [LoginControl.razor] 元件上將會看到登入按鈕
- 而且,在首頁上因為使用了
AuthorizeView
這個 Blazor 內建的元件,因此,將會根據使用者是否有成功通過驗證,而顯示出不同的內容 - 由於現在尚未通過驗證,因此,在首頁上將會顯示尚未通過驗證的訊息
- 請在 [User Name] 與 [Password] 欄位,輸入使用的帳號與密碼 (因為在這個練習專案中,並未實際做使用帳號與密碼的檢查,因此,可以輸入任何內容即可)
- 請點選右上方的 [登入] 按鈕,如下面螢幕截圖
- 在成功通過身分驗證過程,也就是登入成功了,在網頁最上方的 [LoginControl.razor] 元件內容也自動切換成已經登入的狀態
- 並且,在首頁頁面上,也因為成功登入了,顯示出已經登入訊息,這裡的內容將會動態的切換,與尚未成功登入前有所不同
- 因為採用 Cookie 的方式,所以,不論關閉這個網頁,或者開啟一個新的瀏覽器標籤頁次,都會看到如上面螢幕截圖的畫面
更多關於 Blazor 教學影片,可以參考 Blazor 教學影片播放清單 或者 Blazor 快速體驗教學影片撥放清單。也歡迎訂閱本 .NET / Blazor / Xamarin.Forms 影片頻道 。
在這篇文章中,將會說明如何不使用 ASP.NET Core 上的身分識別 功能 (ASP.NET Core 身分識別是支援使用者介面(UI)登入功能的 API。管理使用者、密碼、設定檔資料、角色、宣告、權杖、電子郵件確認等等。),來實作出登入/登出的效果,並且,也將會說明如何設計使用者有登入與沒有登入的時候,將會看到不同的網頁內容。