您现在的位置是:网站首页> 编程资料编程资料

ASP.NET Core 6.0 添加 JWT 认证和授权功能_实用技巧_

2023-05-24 503人已围观

简介 ASP.NET Core 6.0 添加 JWT 认证和授权功能_实用技巧_

序言

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

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

相关名词

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

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

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

认证(Authentication)

基本步骤

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

1 安装 Nuget 包

安装 Microsoft.AspNetCore.Authentication.JwtBearer

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

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

2 准备配置信息

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

"Jwt": { "SecretKey": "lisheng741@qq.com", "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 GetToken() { return _jwtHelper.CreateToken(); } [Authorize] [HttpGet] public ActionResult 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 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 GetUser => "GetUser"; [Authorize(Roles = "admin")] //与控制器的Authorize叠加作用,除了拥有user,还需拥有admin public A
                
                

-六神源码网