簡單服務器端Blazor Cookie身份驗證的演示

爲了演示身份驗證如何在服務器端 Blazor 應用程序中工做,咱們將把身份驗證簡化爲最基本的元素。 咱們將簡單地設置一個 cookie,而後讀取應用程序中的 cookie。html

 

應用程序身份驗證ios

 

大多數商業 web 應用程序都要求用戶登陸到應用程序中。git

 

用戶輸入他們的用戶名和密碼,對照成員資格數據庫進行檢查。github

 

一旦經過身份驗證,該應用程序便可識別用戶,而且如今能夠安全地傳遞內容。web

理解了服務器端 Blazor 應用程序的身份驗證過程,咱們就能夠實現一個知足咱們須要的身份驗證和成員資格管理系統(例如,一個容許用戶建立和管理其用戶賬戶的系統)。數據庫

 

注意:此示例代碼不會檢查是否有人使用了合法的用戶名和密碼! 您將須要添加正確的代碼進行檢查。 這段代碼只是對受權用戶的過程的演示。api

 

 

 

建立應用程序瀏覽器

 

 

打開Visual Studio 2019。安全

 

建立沒有身份驗證的 Blazor 服務器應用程序。服務器

 

 

添加Nuget軟件包

在解決方案資源管理器中,右鍵單擊項目名稱並選擇 Manage NuGet Packages。

 

添加對如下庫的引用:

  • Microsoft.AspNetCore.Authorization
  • Microsoft.AspNetCore.Http
  • Microsoft.AspNetCore.Identity

 

另外還有

  • Microsoft.AspNetCore.Blazor.HttpClient

 

 

添加Cookie身份驗證

 

打開Startup.cs文件。

在文件頂部添加如下using語句:

1 // ******
2 // BLAZOR COOKIE Auth Code (begin)
3 using Microsoft.AspNetCore.Authentication.Cookies;
4 using Microsoft.AspNetCore.Http;
5 using System.Net.Http;
6 // BLAZOR COOKIE Auth Code (end)
7 // ******

 

將Start 類改成以下,添加註釋標記爲 BLAZOR COOKIE Auth Code 的部分:

 1 public class Startup
 2     {
 3         public Startup(IConfiguration configuration)
 4         {
 5             Configuration = configuration;
 6         }
 7         public IConfiguration Configuration { get; }
 8         // This method gets called by the runtime. Use this method to 
 9         // add services to the container.
10         // For more information on how to configure your application, 
11         // visit https://go.microsoft.com/fwlink/?LinkID=398940
12         public void ConfigureServices(IServiceCollection services)
13         {
14             // ******
15             // BLAZOR COOKIE Auth Code (begin)
16             services.Configure<CookiePolicyOptions>(options =>
17  { 18                 options.CheckConsentNeeded = context => true; 19                 options.MinimumSameSitePolicy = SameSiteMode.None; 20  }); 21  services.AddAuthentication( 22  CookieAuthenticationDefaults.AuthenticationScheme) 23  .AddCookie(); 24             // BLAZOR COOKIE Auth Code (end)
25             // ******
26             services.AddRazorPages();
27             services.AddServerSideBlazor();
28             services.AddSingleton<WeatherForecastService>();
29             // ******
30             // BLAZOR COOKIE Auth Code (begin)
31             // From: https://github.com/aspnet/Blazor/issues/1554
32             // HttpContextAccessor
33  services.AddHttpContextAccessor(); 34             services.AddScoped<HttpContextAccessor>(); 35  services.AddHttpClient(); 36             services.AddScoped<HttpClient>(); 37             // BLAZOR COOKIE Auth Code (end)
38             // ******
39         }
40         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
41         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
42         {
43             if (env.IsDevelopment())
44             {
45                 app.UseDeveloperExceptionPage();
46             }
47             else
48             {
49                 app.UseExceptionHandler("/Error");
50                 // The default HSTS value is 30 days. 
51                 // You may want to change this for production scenarios, 
52                 // see https://aka.ms/aspnetcore-hsts.
53                 app.UseHsts();
54             }
55             app.UseHttpsRedirection();
56             app.UseStaticFiles();
57             app.UseRouting();
58             // ******
59             // BLAZOR COOKIE Auth Code (begin)
60  app.UseHttpsRedirection(); 61  app.UseStaticFiles(); 62  app.UseCookiePolicy(); 63  app.UseAuthentication(); 64             // BLAZOR COOKIE Auth Code (end)
65             // ******
66             app.UseEndpoints(endpoints =>
67             {
68                 endpoints.MapBlazorHub();
69                 endpoints.MapFallbackToPage("/_Host");
70             });
71         }
72     }

首先,代碼添加了對cookie的支持。 Cookie由應用程序建立,並在用戶登陸時傳遞到用戶的Web瀏覽器。Web瀏覽器將Cookie傳遞迴應用程序以指示用戶已經過身份驗證。 當用戶「註銷」時,cookie被刪除。

這段代碼還添加了:

  • HttpContextAccessor
  • HttpClient

在代碼中使用依賴注入訪問的服務。

查看這個連接能夠得到關於 httpcontexcessor 如何讓咱們肯定登陸用戶是誰的完整解釋。

 

添加登陸/註銷頁面

登陸(和註銷)由.cshtml頁面執行。

添加如下Razor頁面和代碼:

 

Login.cshtml

1 @page
2 @model BlazorCookieAuth.Server.Pages.LoginModel
3 @{
4     ViewData["Title"] = "Log in";
5 }
6 <h2>Login</h2>

Login.cshtml.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Security.Claims;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Authentication;
 6 using Microsoft.AspNetCore.Authentication.Cookies;
 7 using Microsoft.AspNetCore.Authorization;
 8 using Microsoft.AspNetCore.Mvc;
 9 using Microsoft.AspNetCore.Mvc.RazorPages;
10 namespace BlazorCookieAuth.Server.Pages
11 {
12     [AllowAnonymous]
13     public class LoginModel : PageModel
14     {
15         public string ReturnUrl { get; set; }
16         public async Task<IActionResult> 
17             OnGetAsync(string paramUsername, string paramPassword)
18         {
19             string returnUrl = Url.Content("~/");
20             try
21             {
22                 // 清除現有的外部Cookie
23                 await HttpContext
24                     .SignOutAsync(
25                     CookieAuthenticationDefaults.AuthenticationScheme);
26             }
27             catch { }
28             // *** !!! 在這裏您能夠驗證用戶 !!! ***
29             // 在此示例中,咱們僅登陸用戶(此示例始終登陸用戶)
30             //
31             var claims = new List<Claim>
32             {
33                 new Claim(ClaimTypes.Name, paramUsername),
34                 new Claim(ClaimTypes.Role, "Administrator"),
35             };
36             var claimsIdentity = new ClaimsIdentity(
37                 claims, CookieAuthenticationDefaults.AuthenticationScheme);
38             var authProperties = new AuthenticationProperties
39             {
40                 IsPersistent = true,
41                 RedirectUri = this.Request.Host.Value
42             };
43             try
44             {
45                 await HttpContext.SignInAsync(
46                 CookieAuthenticationDefaults.AuthenticationScheme,
47                 new ClaimsPrincipal(claimsIdentity),
48                 authProperties);
49             }
50             catch (Exception ex)
51             {
52                 string error = ex.Message;
53             }
54             return LocalRedirect(returnUrl);
55         }
56     }
57 }

 

Logout.cshtml

1 @page
2 @model BlazorCookieAuth.Server.Pages.LogoutModel
3 @{
4     ViewData["Title"] = "Logout";
5 }
6 <h2>Logout</h2>

 

Logout.cshtml.cs

 1 using System;
 2 using System.Threading.Tasks;
 3 using Microsoft.AspNetCore.Authentication;
 4 using Microsoft.AspNetCore.Authentication.Cookies;
 5 using Microsoft.AspNetCore.Mvc;
 6 using Microsoft.AspNetCore.Mvc.RazorPages;
 7 namespace BlazorCookieAuth.Server.Pages
 8 {
 9     public class LogoutModel : PageModel
10     {
11         public async Task<IActionResult> OnGetAsync()
12         {
13             // 清除現有的外部Cookie
14             await HttpContext
15                 .SignOutAsync(
16                 CookieAuthenticationDefaults.AuthenticationScheme);
17             return LocalRedirect(Url.Content("~/"));
18         }
19     }
20 }

 

 

 

 

添加客戶代碼

 

使用如下代碼將一個名爲 LoginControl.razor 的頁面添加到 Shared 文件夾:

 1 @page "/loginControl"
 2 @using System.Web;
 3 <AuthorizeView>
 4     <Authorized>
 5         <b>Hello, @context.User.Identity.Name!</b>
 6         <a class="ml-md-auto btn btn-primary"
 7            href="/logout?returnUrl=/"
 8            target="_top">Logout</a>
 9     </Authorized>
10     <NotAuthorized>
11         <input type="text"
12                placeholder="User Name"
13                @bind="@Username" />
14         &nbsp;&nbsp;
15         <input type="password"
16                placeholder="Password"
17                @bind="@Password" />
18         <a class="ml-md-auto btn btn-primary"
19            href="/login?paramUsername=@encode(@Username)&paramPassword=@encode(@Password)"
20            target="_top">Login</a>
21     </NotAuthorized>
22 </AuthorizeView>
23 @code {
24     string Username = "";
25     string Password = "";
26     private string encode(string param)
27     {
28         return HttpUtility.UrlEncode(param);
29     }
30 }

此代碼建立一個登陸組件,該組件使用AuthorizeView組件根據用戶當前的身份驗證包裝標記代碼。

若是用戶已登陸,咱們將顯示其姓名和一個「註銷」按鈕(可將用戶導航到以前建立的註銷頁面)。

若是未登陸,咱們會顯示用戶名和密碼框以及一個登陸按鈕(將用戶導航到以前建立的登陸頁面)。

 

最後,咱們將MainLayout.razor頁面(在Shared文件夾中)更改成如下內容:

 

 1 @inherits LayoutComponentBase
 2 <div class="sidebar">
 3     <NavMenu />
 4 </div>
 5 <div class="main">
 6     <div class="top-row px-4">
 7         <!-- BLAZOR COOKIE Auth Code (begin) -->
 8         <LoginControl />
 9         <!-- BLAZOR COOKIE Auth Code (end) -->
10     </div>
11     <div class="content px-4">
12         @Body
13     </div>
14 </div>

這會將登陸組件添加到Blazor應用程序中每一個頁面的頂部。

 

打開App.razor頁面,並將全部現有代碼包含在 CascadingAuthenticationState 標記中。

 

如今咱們能夠按F5鍵運行該應用程序。

 

咱們能夠輸入用戶名和密碼,而後單擊「登陸」按鈕…

 

而後咱們能夠在 Google Chrome 瀏覽器 DevTools 中看到 cookie 已經被建立。

 

當咱們單擊註銷...

 

Cookie被刪除。

 

 

調用服務器端控制器方法

此時,全部.razor頁面將正確檢測用戶是否已經過身份驗證,並按預期運行。 可是,若是咱們向服務器端控制器發出http請求,則將沒法正確檢測到通過身份驗證的用戶。

爲了演示這一點,咱們首先打開startup.cs頁面,並將如下代碼添加到app.UseEndpoints方法的末尾(在endpoints.MapFallbackToPage(「/ _ Host」)行下),以容許對控制器的http請求 正確路由:

1  // ******
2  // BLAZOR COOKIE Auth Code (begin)
3     endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
4  // BLAZOR COOKIE Auth Code (end)
5  // ******

 

接下來,咱們建立一個Controllers文件夾,並使用如下代碼添加UserController.cs文件:

 

 1 using Microsoft.AspNetCore.Mvc;
 2 namespace BlazorCookieAuth.Controllers
 3 {
 4     [Route("api/[controller]")]
 5     [ApiController]
 6     public class UserController : Controller
 7     {
 8         // /api/User/GetUser
 9         [HttpGet("[action]")]
10         public UserModel GetUser()
11         {
12             // Instantiate a UserModel
13             var userModel = new UserModel
14             {
15                 UserName = "[]",
16                 IsAuthenticated = false
17             };
18             // Detect if the user is authenticated
19             if (User.Identity.IsAuthenticated)
20             {
21                 // Set the username of the authenticated user
22                 userModel.UserName = 
23                     User.Identity.Name;
24                 userModel.IsAuthenticated = 
25                     User.Identity.IsAuthenticated;
26             };
27             return userModel;
28         }
29     }
30     // Class to hold the UserModel
31     public class UserModel
32     {
33         public string UserName { get; set; }
34         public bool IsAuthenticated { get; set; }
35     }
36 }

 

咱們使用如下代碼添加一個新的.razor頁面CallServerSide.razor:

 1 @page "/CallServerSide"
 2 @using BlazorCookieAuth.Controllers
 3 @using System.Net.Http
 4 @inject HttpClient Http
 5 @inject NavigationManager UriHelper
 6 @inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
 7 <h3>Call Server Side</h3>
 8 <p>Current User: @CurrentUser.UserName</p>
 9 <p>IsAuthenticated: @CurrentUser.IsAuthenticated</p>
10 <button class="btn btn-primary" @onclick="GetUser">Get User</button>
11 @code {
12     UserModel CurrentUser = new UserModel();
13     async Task GetUser()
14     {
15         // Call the server side controller
16         var url = UriHelper.ToAbsoluteUri("/api/User/GetUser");
17         var result = await Http.GetJsonAsync<UserModel>(url.ToString());
18         // Update the result
19         CurrentUser.UserName = result.UserName;
20         CurrentUser.IsAuthenticated = result.IsAuthenticated;
21     }
22 }

 

最後,咱們使用如下代碼在Shared / NavMenu.razor中添加指向頁面的連接:

1 <li class="nav-item px-3">
2       <NavLink class="nav-link" href="CallServerSide">
3             <span class="oi oi-list-rich" aria-hidden="true"></span> Call Server Side
4       </NavLink>
5 </li>

 

咱們運行該應用程序並登陸。

 

 

咱們導航到新的Call Server Side控件,而後單擊Get User按鈕(該按鈕將調用剛剛添加的UserController.cs),而且它不會檢測到已登陸的用戶。

要解決此問題,請將CallServerSide.razor頁面中的GetUser方法更改成如下內容:

 1 async Task GetUser()
 2     {
 3         // Code courtesy from Oqtane.org (@sbwalker)
 4         // We must pass the authentication cookie in server side requests
 5         var authToken =
 6         HttpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Cookies"];
 7         if (authToken != null)
 8         {
 9             Http.DefaultRequestHeaders
10             .Add("Cookie", ".AspNetCore.Cookies=" + authToken);
11             // Call the server side controller
12             var url = UriHelper.ToAbsoluteUri("/api/User/GetUser");
13             var result = await Http.GetJsonAsync<UserModel>(url.ToString());
14             // Update the result
15             CurrentUser.UserName = result.UserName;
16             CurrentUser.IsAuthenticated = result.IsAuthenticated;
17         }
18     }

咱們有一個身份驗證cookie,咱們只須要在DefaultRequestHeaders中傳遞它便可。

如今,當咱們登陸並單擊「獲取用戶」按鈕時,控制器方法便可以檢測到已登陸的用戶。

相關文章
相關標籤/搜索