ASP .NET Core 中的身份验证

2025-06-04

ASP .NET Core 中的身份验证

本文介绍了 ASP .NET Core 中的身份验证。它尝试解释这些概念及其关联,并展示一些代码,以便您可以将身份验证添加到您自己的 .NET 应用程序中。

验证用户身份意味着确定用户的真实身份。我们这样做是为了确保用户的身份与其声明相符。一旦我们确认信任他们,我们就可以让他们登录到我们的应用,并向他们展示只有登录用户才能访问的资源。

主要场景

以下是我们要解决的主要场景:

  • 验证用户。
  • 当未经身份验证的用户尝试访问受限资源时做出响应。

处理程序,处理身份验证流程的服务

设置身份验证

要执行身份验证流程,您需要一个处理程序。您可以拥有多个处理程序,但每个处理程序必须实现IAuthenticationService相应的接口。处理程序由身份验证中间件使用。已注册的身份验证处理程序及其配置选项称为“方案”。

一个计划

要使用某个方案,您需要在此处注册Startup.ConfigureServices,如下所示:



void ConfigureServices() 
{
  // register your scheme
}


Enter fullscreen mode Exit fullscreen mode

您需要做的是先调用,AddAuthentication()然后调用特定的方案,如下例所示:



void ConfigureServices() 
{
  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>   Configuration.Bind("JwtSettings", options))
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => Configuration.Bind("CookieSettings", options));
}


Enter fullscreen mode Exit fullscreen mode

这里我们调用了AddAuthentication(),然后又调用了AddJwtBearer()和这两个方案AddCookie()。通过调用这些方案,你可以注册它们以及它们的配置设置。

如果您使用 ASP .NET Identity,则并不总是需要明确调用AddAuthentication(),该调用会在内部为您完成。

设置中间件

为了理解为什么我们要执行此步骤,我们首先来讨论一下请求管道。想象一下以下场景:

调用客户端向系统上的资源发出请求。为了实现这一点,他们需要登录到系统。要登录,用户需要提供凭证(通常是用户名和密码),以证明他们的身份。我们称之为身份验证。但是,我们需要编写代码来确保请求被拦截,并有机会验证用户身份。这就是为什么我们现在需要与中间件交互,并将其配置为使用我们之前在 ASP.NET 中注册的处理程序/方案。

现在我们转到类中Configure()的另一个方法Startup并像这样调用UseAuthentication()



void Configure() 
{
  UseAuthentication();
}


Enter fullscreen mode Exit fullscreen mode

UseAuthentication()您需要在正确的时间调用,以便任何依赖于该授权的程序都可以使用它。以下是一些指导原则:

  • 之后UseRouting(),以便路由信息可用于身份验证决策。
  • 之前UseEndpoints(),以便用户在访问端点之前进行身份验证。

验证用户

验证用户

好的,到目前为止您已经看到了三部分中的两部分:

  1. 注册方案/处理程序
  2. 指示管道使用它
  3. 验证用户身份<-待解释

让我们讨论一下如何验证用户身份。我们将借用一个示例项目中的代码来实现这一点,该示例项目实现了Cookie 身份验证。

注册方案/处理程序

首先,让我们检查 1)在Startup.csConfigureServices()中的方法中方案的注册



public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(CookieScheme) // Sets the default scheme to cookies
            .AddCookie(CookieScheme, options =>
            {
                options.AccessDeniedPath = "/account/denied";
                options.LoginPath = "/account/login";
            });

        // Example of how to customize a particular instance of cookie options and
        // is able to also use other services.
        services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, ConfigureMyCookie>();
    }


Enter fullscreen mode Exit fullscreen mode

AddCookie()注意注册方案和配置的调用AccessDeniedPathLoginPath通过指定这些配置值,我们知道如果用户是以下哪种情况,应该将他们发送到哪条路由:

  • 无法提供凭证/account/denied
  • 提供凭证并登录的地方/account/login

配置中间件

我们已经注册了该方案并准备使用它。下一步是通过调用 明确地告诉我们的应用程序使用它UseAuthentication()



public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}


Enter fullscreen mode Exit fullscreen mode

请注意对的调用app.UseAuthentication()以及它在对的调用之后的UseRouting()方式,因此我们有路由信息,并且在对的调用之前UseEndpoints(),因此后者可以利用身份验证功能。

进行实际身份验证

当我们注册该方案时,我们告诉它在哪里进行登录,也就是/account/login我们需要编写一个控制器类和方法。因此,创建一个AccountController.cs包含以下内容的控制器类:



using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

namespace AuthSamples.Cookies.Controllers;

public class AccountController : Controller
{
}


Enter fullscreen mode Exit fullscreen mode

我们需要在这个类中填充以下内容:

  • 呈现登录表单的方法
  • 处理用户发送的登录凭证并进行验证的方法
  • 一种处理注销的方法

渲染登录表单

这里我们的控制器代码变得简单,如下所示:



[HttpGet]
public IActionResult Login(string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    return View();
}


Enter fullscreen mode Exit fullscreen mode

由于我们有一个渲染Login.cshtml 的模板,所以它变得简单:



<h2>Login</h2>

<div class="row">
    <div class="col-md-8">
        <section>
            <form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
                <div class="form-group">
                    <label class="col-md-2 control-label">User</label>
                    <div class="col-md-10">
                        <input type="text" name="username" />
                    </div>
                </div>

                <div class="form-group">
                    <label class="col-md-2 control-label">Password</label>
                    <div class="col-md-10">
                        <input type="password" name="password" />
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <button type="submit" class="btn btn-default">Log in</button>
                    </div>
                </div>
            </form>
        </section>
    </div>
</div>


Enter fullscreen mode Exit fullscreen mode

上述模板由用户名字段、密码字段和提交按钮组成。

处理登录请求

想象一下,现在用户在上述表单中输入他们的凭证,那么我们需要控制器代码来处理:



private bool ValidateLogin(string userName, string password)
{
    // For this sample, all logins are successful.
    return true;
}

[HttpPost]
public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;

    // Normally Identity handles sign in, but you can do it directly
    if (ValidateLogin(userName, password))
    {
        var claims = new List<Claim>
            {
                new Claim("user", userName),
                new Claim("role", "Member")
            };

        await HttpContext.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "role")));

        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return Redirect("/");
        }
    }

    return View();
}


Enter fullscreen mode Exit fullscreen mode
  • Login()当用户点击登录按钮时,通过 POST 请求调用该方法。我们提供了username调用passwordValidateLogin()这里通常需要调用数据库来验证用户,确保用户存在、密码正确等)。
  • 然后我们登录用户,如果ValidateLogin()响应为真。
  • 当我们调用 时,登录就会发生HttpContext.SignInAsync()。该方法需要ClaimsPrincipal创建一个实例。该对象需要一个对象作为实例。从高层次上讲,我们声明用户是谁,然后可以在授权ClaimsIdentity过程中确定用户可以访问系统的哪些部分

处理注销请求

用户可能想要注销,为了处理这个问题,您可以向您的AccountController类添加另一个方法,如下所示:



public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync();
    return Redirect("/");
}


Enter fullscreen mode Exit fullscreen mode

调用HttpContext.SignOutAsync()将确保应用程序忘记有关您和您的登录会话的所有信息。

这里发生的事情是:

正确路由用户

此时您可能想知道,系统如何知道如何将用户发送到此登录表单,例如,如何检查谁已登录或未登录?

这时我们来看一下HomeController.cs文件。它使用一个特性类,Authorize当用户未通过身份验证时,强制用户进入登录页面。具体实现如下:

  1. 用户尝试前往路线/Home/MyClaims


   [Authorize]
   public IActionResult MyClaims()
   {
      return View();
   }


Enter fullscreen mode Exit fullscreen mode
  1. 如果用户已登录,则会显示MyClaims函数所代表的视图。如果用户未登录,则会转到account/login

概括

希望您现在已经对如何在 ASP .NET 应用程序中对用户进行身份验证和登录有了一个很好的了解。在下一部分中,我们将讨论如何授权用户,即确定哪些用户可以访问哪些资源。

文章来源:https://dev.to/dotnet/authentication-in-asp-net-core-59k8
PREV
使用 Lucene.NET 在 Blazor WebAssembly 中实现搜索
NEXT
.Net Core 中你不可或缺的 10 个命令