NET8中WebAPI使用JWT入门教程

1、JWT

现在在各类API的开发中,token已经是必备了。例如:微信公众号开发中,第一个方法就是获取token。JWT具体的定义及组成部分大家可以到网上找找,这儿给一个简单的描述:JWT 令牌是紧凑的 URL 安全令牌,易于在各方之间转移。它们是自包含的,这意味着它们自身内部携带信息,从而减少了对服务器端会话存储的需求。
定义可以从网上找到,但网上入门的例子,要么很简单、要么很复杂,反而不知道如何入门。因此这儿记录一下,在net8的webapi中如何使用JWT的入门教程。

2、具体实现

首先创建NET8环境下WebApi的项目,通过nuget引用包 Microsoft.AspNetCore.Authentication.JwtBearer
appsettings.json中添加配置信息

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",

  /**JWT的配置信息,这几个信息都是测试数据,需要根据实际业务自行调整**/
  "JwtSettings": {
    "SecretKey": "bAafd@A7d9#@F4*V!LHZs#ebKQrkE6pad2f3kj34c3dXy@", /**存放加密的秘钥**/
    "Issuer": "ZhengLinTest", /**存放发布者信息**/
    "Audience": "AllUseAPI", /**存放受众者信息**/
    "AccessTokenExpirationMinutes": 30,
    "RefreshTokenExpirationDays": 7
  }
}

为了能够将配置文件中JwtSettings强转换为一个类,需要提前定义一个Model类。

namespace JWTWebApplication.Models
{
    /// <summary>
    /// 这个类主要是用于解析appsettings.json里的配置信息,也可以使用其他方式,获取及保存配置信息
    /// </summary>
    public class JwtSettings
    {
        public string SecretKey { get; set; }
        public string Issuer { get; set; }
        public string Audience { get; set; }
        public int AccessTokenExpirationMinutes { get; set; }
        public int RefreshTokenExpirationDays { get; set; }

    }
}

JWT是一加密的符合JSON格式的字符串,那我们就需要定义,到底要加密哪些信息。在本例中我们会加密:姓名、密码、角色、邮箱等信息。因此我们创建一个,用于自定义需要加密到JWT中的信息。具体的Model如下

namespace JWTWebApplication.Models
{
    /// <summary>
    /// 用于存储到token中的数据
    /// </summary>
    public class User
    {
        public int Id { get; set; }
        public string Username { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string[] Roles { get; set; }
    }
}

下面我们会创建一个用于生成JWTService类,并添加一个生成jwt的方法Crete

namespace JWTWebApplication.Services
{
    public class AuthService
    {
	    //通过依赖注入的方式,将配置参数带入到类中。后面会在program.cs文件中,进行注册。
			private readonly JwtSettings _jwtSettings;
			
			public AuthService(IOptions<JwtSettings> jwtSettings)
			{
			    _jwtSettings = jwtSettings.Value;
			}

			/// <summary>
			/// 用于令牌的生成
			/// </summary>
			/// <param name="user"></param>
			/// <returns></returns>
			public string Create(User user)
			{
			}
    }
}

Create方法中,先实例化JwtSecurityTokenHandler,它负责生成token(令牌)

var handler = new JwtSecurityTokenHandler();

下一步是生成令牌的信息并进行签名,因此我们需要刚才配置信息的秘钥,并使用SigningCredentials 完成签名,SigningCredentials 需要两个参数:秘钥和算法

var privateKey = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);

var credentials = new SigningCredentials(
            new SymmetricSecurityKey(privateKey),
            SecurityAlgorithms.HmacSha256);

下一步,就是将我们需要加密到token中的数据,通过方法实现。该如何添加呢?它的代码是这样的:

new Claim(ClaimTypes.Name, user.Username)  //可以理解为键/值结构

为了简化操作,我将创建一个方法来返回我们将保存在令牌中的 ClaimsIdentity(所有令牌声明的列表),该方法会自动添加到令牌的有效负载中。

//准备给Token中的值
private static ClaimsIdentity GenerateClaims(User user)
{
    var ci = new ClaimsIdentity();

    ci.AddClaim(new Claim("id", user.Id.ToString()));
    ci.AddClaim(new Claim(ClaimTypes.Name, user.Username));
    ci.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
    ci.AddClaim(new Claim(ClaimTypes.Email, user.Email));

    foreach (var role in user.Roles)
        ci.AddClaim(new Claim(ClaimTypes.Role, role));

    return ci;
}

下一步操作是创建 SecurityTokenDescriptor 的实例,以便在令牌中包含基本信息

var tokenDescriptor = new SecurityTokenDescriptor
{
    SigningCredentials = credentials,
    Expires = DateTime.UtcNow.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes),
    Subject = GenerateClaims(user)
};

然后我使用handler.CreateToken()方法生成令牌,并且使用handler.WriteToken(token)方法,将JwtSecurityToken序列化为紧凑序列化格式JWT并返回。

var token = handler.CreateToken(tokenDescriptor);
return handler.WriteToken(token);

最终,生成完成的代码如下:

using JWTWebApplication.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace JWTWebApplication.Services
{
    public class AuthService
    {
        //通过依赖注入的方式,将配置参数带入到类中
        private readonly JwtSettings _jwtSettings;

        public AuthService(IOptions<JwtSettings> jwtSettings)
        {
            _jwtSettings = jwtSettings.Value;
        }



        /// <summary>
        /// 用于令牌的生成
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string Create(User user)
        {
            var handler = new JwtSecurityTokenHandler();
            var privateKey = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);

            var credentials = new SigningCredentials(
                        new SymmetricSecurityKey(privateKey),
                        SecurityAlgorithms.HmacSha256);


            var tokenDescriptor = new SecurityTokenDescriptor
            {
                SigningCredentials = credentials,
                Expires = DateTime.UtcNow.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes),
                Subject = GenerateClaims(user)
            };

            var token = handler.CreateToken(tokenDescriptor);
            return handler.WriteToken(token);

        }

        //准备给Token中的值
        private static ClaimsIdentity GenerateClaims(User user)
        {
            var ci = new ClaimsIdentity();

            ci.AddClaim(new Claim("id", user.Id.ToString()));
            ci.AddClaim(new Claim(ClaimTypes.Name, user.Username));
            ci.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
            ci.AddClaim(new Claim(ClaimTypes.Email, user.Email));

            foreach (var role in user.Roles)
                ci.AddClaim(new Claim(ClaimTypes.Role, role));

            return ci;
        }
    }
}

有了生成token的方法,那我们就需要进行配置,准备使用了。具体来说,就是在program.cs中进行配置
首先添加开启授权和认证功能的代码

builder.Services.AddAuthentication();//启用身份验证功能--认证主要是指,用户米、密码是否正确
builder.Services.AddAuthorization();//启用授权功能---授权主要是看有没有权限

app.UseAuthentication(); //启用认证功能
app.UseAuthorization(); //启用授权功能

其次,要指定使用 JWT 进行身份验证,需要进行配置调整。这涉及设置 DefaultChallengeScheme 以定义如何检查每个传入请求以确定适当的身份验证方法。这可确保应用程序收到的每个请求都被视为 JWT 身份验证

builder.Services.AddAuthentication(x =>  
{  
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;  
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;  
});

此外,可以通过 AddJwtBearer()方法进行验证令牌。在本例中,将使用私钥,并且为了简单起见,排除了对颁发者和受众的验证

//收到的每个请求都被视为 JWT 身份验证
builder.Services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
    };
});

因为有些类,用到了依赖注入的方式实现,因此在配置文件中加了一下依赖注入的声明

//依赖注入
builder.Services.AddTransient<AuthService>();
builder.Services.AddOptions();
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));

因此,完成的配置文件如下:

using JWTWebApplication.Models;
using JWTWebApplication.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Options;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//依赖注入
builder.Services.AddTransient<AuthService>();
builder.Services.AddOptions();
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));

//启用功能
builder.Services.AddAuthentication();//启用身份验证功能--认证主要是指,用户米、密码是否正确
builder.Services.AddAuthorization();//启用授权功能---授权主要是看有没有权限

//读取配置文件的数据
//这儿自定义了一个JwtSettings类,类里面的属性要与配置文件中的一致
var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();

//收到的每个请求都被视为 JWT 身份验证
builder.Services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
    };
});

//声明一个指定名称的认证策略
builder.Services.AddAuthorization(x =>
{
    x.AddPolicy("rolePolicy", p => p.RequireRole("developer"));
});


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthentication(); //启用认证功能
app.UseAuthorization(); //启用授权功能

app.MapControllers();

app.Run();

至此,基本的配置已经完成,让我们开始使用吧
首先,先创建一个api的Controller,并写下如下的代码

namespace JWTWebApplication.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JWTTestController : ControllerBase
    {
	    //依赖注入。在program文件中的依赖注入,这儿就用到了
			private readonly AuthService _authService;
			public JWTTestController(AuthService authService)
			{
			    _authService = authService;
			}

			//具体的三个方法实现
    }
}

在类里面,我们将会创建三个方法:Logintestroletest。这三个方法分别用于:根据传入的用户米/密码,生成tokentestroletest分别用于测试权限认证和测试指定认证名称(就是在program中的x.AddPolicy("rolePolicy", p => p.RequireRole("developer"));),完整的代码如下:

namespace JWTWebApplication.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JWTTestController : ControllerBase
    {
        //依赖注入
        private readonly AuthService _authService;
        public JWTTestController(AuthService authService)
        {
            _authService = authService;
        }

        [HttpGet]
        public string Login(string username,string password)
        {
            //获取前台传过来的用户名、密码的数据
            var user = new User();
            user.Username = username;
            user.Password = password;

            //从后台进行身份验证,并获取该登录人的其他信息(例如,角色、邮箱等各类信息)
            user.Name = "zhenglin";
            user.Id = 1;
            user.Email = "zhenglin@163.com";
            user.Roles = new string[] { "developer" };

            //返回token
            return _authService.Create(user);
        }

        [Authorize]
        [HttpGet]
        public StatusCodeResult test()
        {
            return StatusCode(200);
        }

        [Authorize("rolePolicy")]
        [HttpGet]
        public StatusCodeResult roletest()
        {
            return StatusCode(200);
        }
    }
}

至此,全部代码完成,准备验证
首先测试一下Login,看能否返回token
在这里插入图片描述其次,测试一下携带tokentest方法
在这里插入图片描述
最后测试一下,指定名称的认证
在这里插入图片描述

3、代码下载

代码下载:下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值