zoukankan      html  css  js  c++  java
  • 简单服务器端Blazor Cookie身份验证的演示

    为了演示身份验证如何在服务器端 Blazor 应用程序中工作,我们将把身份验证简化为最基本的元素。 我们将简单地设置一个 cookie,然后读取应用程序中的 cookie。

    应用程序身份验证

    大多数商业 web 应用程序都要求用户登录到应用程序中。

    用户输入他们的用户名和密码,对照成员资格数据库进行检查。

    一旦通过身份验证,该应用程序即可识别用户,并且现在可以安全地传递内容。

    理解了服务器端 Blazor 应用程序的身份验证过程,我们就可以实现一个满足我们需要的身份验证和成员资格管理系统(例如,一个允许用户创建和管理其用户帐户的系统)。

    注意:此示例代码不会检查是否有人使用了合法的用户名和密码! 您将需要添加正确的代码进行检查。 这段代码只是对授权用户的过程的演示。

    创建应用程序

    打开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中传递它即可。

    现在,当我们登录并单击“获取用户”按钮时,控制器方法便能够检测到已登录的用户。

  • 相关阅读:
    springboot整合mybatis增删改查(一):项目创建
    springboot结合开源editor.md集成markdonw编辑器
    springboot发送邮件
    史上最全web.xml配置文件元素详解
    一套简约漂亮的响应式博客园主题皮肤分享给你们(二)
    一套简约漂亮的响应式博客园主题皮肤分享给你们(一)
    IDEA中项目统一编码格式设置
    windows上安装Gradle并配置环境变量
    linux自学(九)之开始centos学习,安装数据库MariaDB
    linux自学(七)之开始ccentos学习,安装jdk
  • 原文地址:https://www.cnblogs.com/bisslot/p/12444967.html
Copyright © 2011-2022 走看看