首页 > 编程语言 >ASP.NET Core 6.0 添加 JWT 认证和授权

ASP.NET Core 6.0 添加 JWT 认证和授权

时间:2022-11-23 00:22:56浏览次数:74  
标签:Authorize Core ASP JWT 授权 Policy new configuration public

原文:http://www.manongjc.com/detail/29-dtuskmzuwjitnoh.html

本文章向大家介绍ASP.NET Core 6.0 添加 JWT 认证和授权,主要包括ASP.NET Core 6.0 添加 JWT 认证和授权使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

序言

本文将分别介绍 Authentication(认证) 和 Authorization(授权)。

并以简单的例子在 ASP.NET Core 6.0 的 WebAPI 中分别实现这两个功能。


相关名词

Authentication 和 Authorization 长得很像,傻傻分不清楚。

Authentication(认证):标识用户的身份,一般发生在登录的时候。

Authorization(授权):授予用户权限,指定用户能访问哪些资源;授权的前提是知道这个用户是谁,所以授权必须在认证之后。


认证(Authentication)

基本步骤

  1. 安装相关 Nuget 包:Microsoft.AspNetCore.Authentication.JwtBearer
  2. 准备配置信息(密钥等)
  3. 添加服务
  4. 调用中间件
  5. 实现一个 JwtHelper,用于生成 Token
  6. 控制器限制访问(添加 Authorize 标签)

1 安装 Nuget 包

安装 Microsoft.AspNetCore.Authentication.JwtBearer

在程序包管理器控制台中:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 6.0.1

2 准备配置信息

在 appsetting.json 中,添加一个 Jwt 节点

"Jwt": {
    "SecretKey": "[email protected]",
    "Issuer": "WebAppIssuer",
    "Audience": "WebAppAudience"
}

3 添加服务

在 Program.cs 文件中注册服务。

// 引入所需的命名空间
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

// ……
var configuration = builder.Configuration;

// 注册服务
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = true, //是否验证Issuer
        ValidIssuer = configuration["Jwt:Issuer"], //发行人Issuer
        ValidateAudience = true, //是否验证Audience
        ValidAudience = configuration["Jwt:Audience"], //订阅人Audience
        ValidateIssuerSigningKey = true, //是否验证SecurityKey
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"])), //SecurityKey
        ValidateLifetime = true, //是否验证失效时间
        ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒)
        RequireExpirationTime = true,
    };
});

4 调用中间件

调用 UseAuthentication(认证),必须在所有需要身份认证的中间件前调用,比如 UseAuthorization(授权)。

// ……
app.UseAuthentication();
app.UseAuthorization();
// ……

5 JwtHelper 类实现

主要是用于生成 JWT 的 Token。

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace TestWebApi;

public class JwtHelper
{
    private readonly IConfiguration _configuration;

    public JwtHelper(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string CreateToken()
    {
        // 1. 定义需要使用到的Claims
        var claims = new[]
        {
            new Claim(ClaimTypes.Name, "u_admin"), //HttpContext.User.Identity.Name
            new Claim(ClaimTypes.Role, "r_admin"), //HttpContext.User.IsInRole("r_admin")
            new Claim(JwtRegisteredClaimNames.Jti, "admin"),
            new Claim("Username", "Admin"),
            new Claim("Name", "超级管理员")
        };

        // 2. 从 appsettings.json 中读取SecretKey
        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));

        // 3. 选择加密算法
        var algorithm = SecurityAlgorithms.HmacSha256;

        // 4. 生成Credentials
        var signingCredentials = new SigningCredentials(secretKey, algorithm);

        // 5. 根据以上,生成token
        var jwtSecurityToken = new JwtSecurityToken(
            _configuration["Jwt:Issuer"],     //Issuer
            _configuration["Jwt:Audience"],   //Audience
            claims,                          //Claims,
            DateTime.Now,                    //notBefore
            DateTime.Now.AddSeconds(30),    //expires
            signingCredentials               //Credentials
        );

        // 6. 将token变为string
        var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

        return token;
    }
}

该 JwtHelper 依赖于 IConfiguration(为了读取配置文件),将 JwtHelper 的创建交由 DI 容器,在 Program.cs 中添加服务:

var configuration = builder.Configuration;
builder.Services.AddSingleton(new JwtHelper(configuration));

将 JwtHelper 注册为单例模式。

6 控制器配置

新建一个 AccountController,以构造函数方式注入 JwtHelper,添加两个 Action:GetToken 用于获取 Token,GetTest 打上 [Authorize] 标签用于验证认证。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace TestWebApi.Controllers;

[Route("api/[controller]/[action]")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly JwtHelper _jwtHelper;

    public AccountController(JwtHelper jwtHelper)
    {
        _jwtHelper = jwtHelper;
    }

    [HttpGet]
    public ActionResult<string> GetToken()
    {
        return _jwtHelper.CreateToken();
    }

    [Authorize]
    [HttpGet]
    public ActionResult<string> GetTest()
    {
        return "Test Authorize";
    }
}

7 测试调用

方式一:通过 Postman、Apifox 等接口调试软件调试

使用 Postman 调用 /api/Account/GetToken 生成 Token

在调用 /api/Account/GetTest 时传入 Token,得到返回结果

方式二:在浏览器控制台调试

调试 /api/Account/GetToken

var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function() {
   if(this.readyState === 4) {
      console.log(token = this.responseText); //这里用了一个全局变量 token,为下一个接口服务
   }
});
xhr.open("GET", "/api/Account/GetToken");
xhr.send();

调试 /api/Account/GetTest

var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function() {
   if(this.readyState === 4) {
      console.log(this.status, this.responseText); //this.status为响应状态码,401为无认证状态
   }
});
xhr.open("GET", "/api/Account/GetTest");
xhr.setRequestHeader("Authorization",`Bearer ${token}`); //附带上 token
xhr.send();

授权(Authorization)

注意:授权必须基于认证,即:若没有完成上文关于认证的配置,则下面的授权是不会成功的。

授权部分,将先介绍相关标签、授权方式,再介绍基于策略的授权。这三部分大致的内容如下描述:

相关标签:Authorize 和 AllowAnonymous

授权方式:介绍 Policy、Role、Scheme 的基本内容

基于策略(Policy)的授权:深入 Policy 授权方式

相关标签(Attribute)

授权相关标签具体请查考官方文档简单授权

[Authorize]

打上该标签的 Controller 或 Action 必须经过认证,且可以标识需要满足哪些授权规则。

授权规则可以是 Policy(策略)、Roles(角色) 或 AuthenticationSchemes(方案)。

[Authorize(Policy = "", Roles ="", AuthenticationSchemes ="")]

[AllowAnonymous]

允许匿名访问,级别高于 [Authorize] ,若两者同时作用,将生效 [AllowAnonymous]

授权方式

基本上授权只有:Policy、Role、Scheme 这3种方式,对应 Authorize 标签的3个属性。

1 Policy(策略)

推荐的授权方式,在 ASP.NET Core 的官方文档提及最多的。一个 Policy 可以包含多个要求(要求可能是 Role 匹配,也可能是 Claims 匹配,也可能是其他方式。)

下面举个基础例子(说是基础例子,主要是基于 Policy 的授权方式可以不断深入追加一些配置):

在 Program.cs 中,添加两条 Policy:

policy1 要求用户拥有一个 Claim,其 ClaimType 值为 EmployeeNumber。

policy2 要求用户拥有一个 Claim,其 ClaimType 值为 EmployeeNumber,且其 ClaimValue 值为1、2、3、4 或 5。

builder.Services.AddAuthorization(options => {
    options.AddPolicy("policy1", policy => policy.RequireClaim("EmployeeNumber"));
    options.AddPolicy("policy2", policy => policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
})

在控制器中添加 [Authorize] 标签即可生效:

[Authorize(Policy = "policy1")]
public class TestController : ControllerBase

或在控制器的 Action 上:

public class TestController : ControllerBase
{
    [Authorize(Policy = "policy1")]
    public ActionResult<string> GetTest => "GetTest";
}

2 Role(角色)

基于角色授权,只要用户拥有角色,即可通过授权验证。

在认证时,给用户添加角色相关的 Claim ,即可标识用户拥有的角色(注:一个用户可以拥有多个角色的 Claim),如:

new Claim(ClaimTypes.Role, "admin"),
new Claim(ClaimTypes.Role, "user")

在 Controller 或 Action 中:

[Authorize(Roles = "user")]
public class TestController : ControllerBase
{
    public ActionResult<string> GetUser => "GetUser";
    
    [Authorize(Roles = "admin")] //与控制器的Authorize叠加作用,除了拥有user,还需拥有admin
    public ActionResult<string> GetAdmin => "GetAdmin";
    
    [Authorize(Roles = "user,admin")] //user 或 admin 其一满足即可
    public ActionResult<string> GetUserOrAdmin => "GetUserOrAdmin";
}

3 Scheme(方案)

方案如:Cookies 和 Bearer,当然也可以是自定义的方案。

由于这种方式不常用,这里不做展开,请参考官方文档按方案限制标识

基于策略(Policy)的授权

上面已经提及了一个基于策略授权的基础例子,下面将继续深入这种授权方式。

1 授权过程

在不断深入 Policy 这种方式的授权之前,有必要将授权的过程描述一下。授权过程描述建议结合源码查看,这样能更清楚其中的作用。当然,这一部分是比较难懂,笔者表述可能也不够清晰,而这一部分对于完成授权的配置也不会有影响,故而如果读者看不明白或无法理解,可以暂且跳过,不必纠结。

建议看一下ASP.NET Core 认证与授权6:授权策略是怎么执行的?这篇文章,文章将授权相关的源码整理出来了,并说明了其中的关系。

这里简单梳理一下:

与授权相关的 interface 和 class 如下:

IAuthorizationService #验证授权的服务,主要方法AuthorizeAsync
DefaultAuthorizationService #IAuthorizationService的默认实现
IAuthorizationHandler #负责检查是否满足要求,主要方法HandleAsync
IAuthorizationRequirement #只有属性,没有方法;用于标记服务,以及用于追踪授权是否成功的机制。
AuthorizationHandler<TRequirement> #主要方法HandleRequirementAsync

这些 interface 和 class 的关系以及授权过程是这样的:

DefaultAuthorizationService 实现 IAuthorizationService 的 AuthorizeAsync 方法。

AuthorizeAsync 方法会获取到所有实现了 IAuthorizationHandler 的实例,并循环调用所有实例的 HandleAsync 方法检查是否满足授权要求,如果有任一一个 HandleAsync 返回了 Fail 则将结束循环(细节请参考官方文档处理程序返回结果),并禁止用户访问。

IAuthorizationHandler 的作用如上一点所述,提供了一个 HandleAsync 方法,用于检查授权。

IAuthorizationRequirement 是一个要求,主要是配合 AuthorizationHandler<TRequirement> 使用。

AuthorizationHandler<TRequirement> 实现了 IAuthorizationHandler 的 HandleAsync 方法,并提供了一个 HandleRequirementAsync 的方法。HandleRequirementAsync 用于检查 Requirement(要求)是否满足。HandleAsync 的默认实现为获取所有实现 TRequirement 的请求(且该请求由 Policy 添加进列表里),循环调用 HandleRequirementAsync,检查哪个要求(Requirement)能满足授权。

简述一下:

[Authorize] 标签生效时,调用的是 IAuthorizationService 的 AuthorizeAsync(由 DefaultAuthorizationService 实现)。

AuthorizeAsync 会去调用所有 IAuthorizationHandler 的 HandleAsync (由 AuthorizationHandler<TRequirement> 实现)。

HandleAsync 会去调用 AuthorizationHandler<TRequirement> 的HandleRequirementAsync 的方法。

注意:这里只是列出了主要的接口和类,部分没有列出,如:IAuthorizationHandlerProvider(这个接口的默认实现 DefaultAuthorizationHandlerProvider,主要是用于收集 IAuthorizationHandler 并返回 IEnumerable<IAuthorizationHandler>

标签:Authorize,Core,ASP,JWT,授权,Policy,new,configuration,public
From: https://www.cnblogs.com/bruce1992/p/16916977.html

相关文章

  • JWT( JSON Web Token —— JSON Web 令牌 )的学习笔记
    一、跨域认证的问题互联网服务离不开用户认证。一般流程是下面这样:1、用户向服务器发送用户名和密码。2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用......
  • excel下载,JasperReports输出pdf
    ~~~java/***导出Excel报表*@return*/@RequestMapping("/exportBusinessReport")publicResultexportBusinessReport(HttpServletRequestrequest,HttpServletRespo......
  • asp.net core mvc异常处理
    过滤器处理异常publicclassGlobalExceptionFilter:IExceptionFilter{privateILogger_logger;publicGlobalExceptionFilter(ILoggerlogger){_logger=logger......
  • Simple JWT
    目录SimpleJWT简单实现生成token及验证获取token刷新token自定义使用email或者phone登陆定制化payload和token(双token)自定义生成token(可塑性高)双token单token认证和权......
  • Nginx underscores_in_headers和ignore_invalid_headers的作用,自我理解的作用。
    underscores_in_headers直达underscores_in_headers启用或禁用在客户端请求标头字段中使用下划线。当禁用下划线时,名称包含下划线的请求标头字段将被标记为无效并受制于......
  • Average Score
     AverageScoreBobisafreshmaninMarjarUniversity.Heiscleveranddiligent.However,heisnotgoodatmath,especiallyinMathematicalAnalysis.Afte......
  • 求超大文件上传方案( asp.net )
    ​ 我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用。这次项目的需求:支持大文件的上传和续传,要求续传支持......
  • asp.net中ScriptManager是做什么用的
    https://zhidao.baidu.com/question/477322362.html命名空间:System.Web.UI程序集:System.Web.Extensions.dll功能跟Page上的ClientScript差不多,不过主要是用来支持ASP.N......
  • 【Core Java Volume1】重写equals,hashCode,toString方法
    1重写equals()方法:例:重写父类Employee3的equals方法//重写equals//1显示命名参数otherObject,稍后转化为otherpublicbooleanequals(ObjectotherObject){//2检......
  • 【Core Java Volume 5】集合算法---查找数组、集合最大值的通用方法
    一、查找数组的最大值1 笔试的时候通常查找数组的最大值,数组类型通常是int类型,可以这样直接写出getMax()代码://数组(int类型)publicstaticintgetMax(int[]nums){......