简单服务器端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="/[email protected](@Username)&[email protected](@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中传递它即可。

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

原文地址:https://www.cnblogs.com/bisslot/p/12444967.html

时间: 2024-08-03 08:09:55

简单服务器端Blazor Cookie身份验证的演示的相关文章

asp.net core中使用cookie身份验证

配置 在 Startup.ConfigureServices 方法中,创建具有 AddAuthentication 和 AddCookie 方法的身份验证中间件服务: services.AddAuthentication(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { // Cookie settings o

ASP.NET MVC Cookie 身份验证

1 创建一个ASP.NET MVC 项目 添加一个 AccountController 类. public class AccountController : Controller { [HttpGet] public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } [HttpPost] public ActionResult Login(string userName,

JAX-RS REST客户端实现基本身份验证机制

<JAX-RS REST客户端实现基本身份验证机制> 作者:chszs,版权所有,未经同意,不得转载.博主主页:http://blog.csdn.net/chszs 很多SaaS API项目提供了HTTP访问的基本身份验证机制.因此,本文提供了如何在JAX-RS REST客户端实现基本的访问认证.有些HTTP客户端库提供了基本身份验证过滤器,使用这些库会更简单. 1.基本的身份验证机制 简单来说,基本的身份验证机制是在服务器端实现的身份验证机制,只需要客户端提供用户名和密码即可,但是它对于HT

将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序

https://weblog.west-wind.com/posts/2015/Apr/29/Adding-minimal-OWIN-Identity-Authentication-to-an-Existing-ASPNET-MVC-Application 将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序 2015年4月29日•来自毛伊岛,HI•    40条评论 从ASP.NET 4开始,ASP.NET提供了一个相当有用的身份系统.如果您创建一个新项目并选择一个MVC项目并选

asp.net core 3.x 身份验证-2启动阶段的配置

注册服务.配置选项.添加身份验证方案 在Startup.ConfigureServices执行services.AddAuthentication() 注册如下服务(便于理解省略了部分辅助服务): services.TryAddScoped<IAuthenticationService, AuthenticationService>(); services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandler

采用Asp.Net的Forms身份验证时,持久Cookie的过期时间会自动扩展

问题描述 之前没有使用Forms身份验证时,如果在登陆过程中把持久的Cookie过期时间设为半个小时,总会收到很多用户的抱怨,说登陆一会就过期了. 所以总是会把Cookie过期时间设的长一些,比如两个小时甚至一天,这样就能保证在登陆时设置一次Cookie,用户可以操作很长时间也不过期. 虽然也可以在每次用户请求页面时检查Cookie的过期时间并自动扩展,但未免过于麻烦,不如一次设大点来的简单. 偶然发现 今天在使用Forms身份验证编写<AppBox-基于ExtAspNet的企业通用管理框架>

无password身份验证:安全、简单且部署高速

Passwordless authentication: Secure, simple, and fast to deploy [编者按]本文作者为 Florian Heinemann 与 Robert Nyman. Florian 来自 MIT 系统设计与管理学院,专注于复杂的社交技术系统.此前曾在企业软件领域的多家初创公司工作,之后加入 Airbus,担任知识与创新管理经理一职.Robert 是 Mozilla Hacks 技术传道师及编辑.曾就 HTML5,JavaScript 以及 Op

采用Asp.Net的Forms身份验证时,非持久Cookie的过期时间会自动扩展

问题描述 之前没有使用Forms身份验证时,如果在登陆过程中把HttpOnly的Cookie过期时间设为半个小时,总会收到很多用户的抱怨,说登陆一会就过期了. 所以总是会把Cookie过期时间设的长一些,比如两个小时甚至一天,这样就能保证在登陆时设置一次Cookie,用户可以操作很长时间也不过期. 虽然也可以在每次用户请求页面时检查Cookie的过期时间并自动扩展,但未免过于麻烦,不如一次设大点来的简单. 偶然发现 今天在使用Forms身份验证编写<AppBox-基于ExtAspNet的企业通用

Shiro处理简单的身份验证的分析及实例

在两天在看Shiro,开涛兄的教程还是写的比较易读,差不多看了一天吧,就准备拿来用了. 可能是想的太简单了,在用的时候确实碰到一些问题,就拿最简单的身份验证来说吧: 需要说明的是,这里是集成在Spring中使用,身份验证我直接使用了Shiro提供的 org.apache.shiro.web.filter.authc.FormAuthenticationFilter 如果url应用了该拦截器,那么处理流程是大致这样的: 由于之前用markdown花的流程图显示不下,所以还是改成图片形式了. 比如我