Administrator
发布于 2024-04-18 / 13 阅读
0
0

.net8 简化的 AddJwtBearer 认证

开发环境

系统版本:win10

.NET SDK: NET8

开发工具:vscode

参考引用:使用 dotnet user-jwts 管理开发中的 JSON Web 令牌(learn.microsoft.com/zh-cn/aspnet/core/security/authentication/jwt-authn?view=aspnetcore-8.0&tabs=windows)

注意:以下示例中的端口、token等需替换成你的环境中的信息

创建项目

运行以下命令来创建一个空的 Web 项目,并添加 Microsoft.AspNetCore.Authentication.JwtBearer NuGet 包:

dotnetnewweb-oMyJWTcdMyJWTdotnetaddpackageMicrosoft.AspNetCore.Authentication.JwtBearer

将 Program.cs 的内容替换为以下代码(略微改动):

using System.Security.Claims;

varbuilder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization;// 默认的Scheme是Bearer// builder.Services.AddAuthentication("Bearer").AddJwtBearer;builder.Services.AddAuthentication.AddJwtBearer;

varapp = builder.Build;

app.UseAuthorization;

app.MapGet("/", =>"Hello, World!");app.MapGet("/secret", (ClaimsPrincipal user) =>$"Hello {user.Identity?.Name}. My secret").RequireAuthorization;

app.Run;

运行项目并访问接口返回以下内容

PS D:\Learn\MyJWT> curl.exe -i http:///localhost:5276HTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8Date: Mon, 04 Dec 2023 00:43:03 GMT Server: KestrelTransfer-Encoding: chunked

Hello, World!

创建 JWT

PSD:\Learn\MyJWT> dotnet user-jwts createNewJWT saved with ID 'c28b968'.Name: Lingpeng

Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IkxpbmdwZW5nIiwic3ViIjoiTGluZ3BlbmciLCJqdGkiOiJjMjhiOTY4IiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6Mjk3NTQiLCJodHRwczovL2xvY2FsaG9zdDo0NDM2MCIsImh0dHA6Ly9sb2NhbGhvc3Q6NTI3NiIsImh0dHBzOi8vbG9jYWxob3N0OjcyNTMiXSwibmJmIjoxNzAxNjQ5Nzk2LCJleHAiOjE3MDk1MTIxOTYsImlhdCI6MTcwMTY0OTc5NiwiaXNzIjoiZG90bmV0LXVzZXItand0cyJ9.l52s9_7oNjIKL96TysgdE0k970fUS9FoLTu2xRs-IPo

这个命令做了3件事:

  1. 更新项目的 appsettings.Development.json,添加了Authentication节点

  2. 更新项目的 MyJWT.csproj,添加了UserSecretsId 配置

  3. 创建了机密文件 %APPDATA%\Microsoft\UserSecrets\<secrets_GUID>\user-jwts.json与%APPDATA%\Microsoft\UserSecrets\<secrets_GUID>\secrets.json,机密管理参考

我们看下这两个机密文件

user-jwts.json

{"c28b968": {"Id": "c28b968","Scheme": "Bearer","Name": "Lingpeng","Audience": "http://localhost:29754, https://localhost:44360, http://localhost:5276, https://localhost:7253","NotBefore": "2023-12-04T00:29:56+00:00","Expires": "2024-03-04T00:29:56+00:00","Issued": "2023-12-04T00:29:56+00:00","Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IkxpbmdwZW5nIiwic3ViIjoiTGluZ3BlbmciLCJqdGkiOiJjMjhiOTY4IiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6Mjk3NTQiLCJodHRwczovL2xvY2FsaG9zdDo0NDM2MCIsImh0dHA6Ly9sb2NhbGhvc3Q6NTI3NiIsImh0dHBzOi8vbG9jYWxob3N0OjcyNTMiXSwibmJmIjoxNzAxNjQ5Nzk2LCJleHAiOjE3MDk1MTIxOTYsImlhdCI6MTcwMTY0OTc5NiwiaXNzIjoiZG90bmV0LXVzZXItand0cyJ9.l52s9_7oNjIKL96TysgdE0k970fUS9FoLTu2xRs-IPo","Scopes": [],"Roles": [],"CustomClaims": {}}}

secrets.json

{"Authentication:Schemes:Bearer:SigningKeys": [{"Id": "ff20683d","Issuer": "dotnet-user-jwts","Value": "lDOFmIuEDelFKU0zAaLoT2qYOFDRZGDDTv5FyTa36V8=","Length": 32}]}

测试JWT

我们重新运行程序,用直接访问与携带token两种方式访问/secret接口

PS D:\Learn\MyJWT> curl.exe -i http://localhost:5276/secretHTTP/1.1 401 UnauthorizedContent-Length: 0Date: Mon, 04 Dec 2023 00:43:25 GMTServer: KestrelWWW-Authenticate: Bearer

PS D:\Learn\MyJWT> PS D:\Learn\MyJWT> PS D:\Learn\MyJWT> curl.exe -i -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IkxpbmdwZW5nIiwic3ViIjoiTGluZ3BlbmciLCJqdGkiOiJjMjhiOTY4IiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6Mjk3NTQiLCJodHRwczovL2xvY2FsaG9zdDo0NDM2MCIsImh0dHA6Ly9sb2NhbGhvc3Q6NTI3NiIsImh0dHBzOi8vbG9jYWxob3N0OjcyNTMiXSwibmJmIjoxNzAxNjQ5Nzk2LCJleHAiOjE3MDk1MTIxOTYsImlhdCI6MTcwMTY0OTc5NiwiaXNzIjoiZG90bmV0LXVzZXItand0cyJ9.l52s9_7oNjIKL96TysgdE0k970fUS9FoLTu2xRs-IPo"http://localhost:5276/secretHTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8Date: Mon, 04 Dec 2023 00:45:42 GMTServer: KestrelTransfer-Encoding: chunked

Hello Lingpeng. My secret

至此我们已经实现了JwtBearer的初步使用

一点点改动

示例采用了机密管理,我们也可以把机密文件中的内容迁移至项目中(推荐用机密管理),我们修改MyJWT.csproj与appsettings.Development.json如下

<ProjectSdk="Microsoft.NET.Sdk.Web">

<PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><!-- <UserSecretsId>88d7c163-def1-4747-b01f-cefed382beae</UserSecretsId> --></PropertyGroup>

<ItemGroup><PackageReferenceInclude="Microsoft.AspNetCore.Authentication.JwtBearer"Version="8.0.0"/></ItemGroup>

</Project>

{"Logging": {"LogLevel": {"Default":"Information","Microsoft.AspNetCore":"Warning"}},"Authentication": {"Schemes": {"Bearer": {"ValidAudiences": ["http://localhost:29754","https://localhost:44360","http://localhost:5276","https://localhost:7253"],"ValidIssuer":"dotnet-user-jwts","SigningKeys": [{"Id":"ff20683d","Issuer":"dotnet-user-jwts","Value":"lDOFmIuEDelFKU0zAaLoT2qYOFDRZGDDTv5FyTa36V8=","Length":32}]}}}}

修改完成后实现相同的功能

JWT Token生成示例

app.MapGet("/login", (stringUserName, stringPassword, [FromServices] IOptionsMonitor<JwtBearerOptions> optionsMonitor) =>{// 1. 密码验证// TODO

// 2. 生成 varparameters = optionsMonitor.Get(JwtBearerDefaults.AuthenticationScheme).TokenValidationParameters;varsigningKey = parameters.IssuerSigningKeys.First;varsigningCredentials = newSigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature);varheader = newJwtHeader(signingCredentials);varpayload = newJwtPayload {{ JwtRegisteredClaimNames.UniqueName, UserName },{ JwtRegisteredClaimNames.Iss, parameters.ValidIssuers.First },{ JwtRegisteredClaimNames.Aud, parameters.ValidAudiences },{ JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds },{ JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds },{ JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds }};varjwtSecurityToken = newJwtSecurityToken(header, payload);varjwtSecurityTokenHandler = newJwtSecurityTokenHandler;vartoken = jwtSecurityTokenHandler.WriteToken(jwtSecurityToken);returntoken;});

进行一下验证

PS D:\Learn\MyJWT> curl.exe -i "http://localhost:5276/login?username=admin&password=1111"HTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8Date: Mon, 04 Dec 2023 05:03:36 GMTServer: KestrelTransfer-Encoding: chunked

eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFkbWluIiwiaXNzIjoiZG90bmV0LXVzZXItand0cyIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjI5NzU0IiwiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNjAiLCJodHRwOi8vbG9jYWxob3N0OjUyNzYiLCJodHRwczovL2xvY2FsaG9zdDo3MjUzIl0sImlhdCI6MTcwMTY2NjIxNiwibmJmIjoxNzAxNjY2MjE2LCJleHAiOjE3MDE2NjgwMTZ9.P9t7vIFfM7cddRPs4OQUTVVdo57nWTLt_ea2UynGUpoPS D:\Learn\MyJWT>PS D:\Learn\MyJWT>PS D:\Learn\MyJWT> curl.exe -i -H "Authorization: Bearer eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFkbWluIiwiaXNzIjoiZG90bmV0LXVzZXItand0cyIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjI5NzU0IiwiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNjAiLCJodHRwOi8vbG9jYWxob3N0OjUyNzYiLCJodHRwczovL2xvY2FsaG9zdDo3MjUzIl0sImlhdCI6MTcwMTY2NjIxNiwibmJmIjoxNzAxNjY2MjE2LCJleHAiOjE3MDE2NjgwMTZ9.P9t7vIFfM7cddRPs4OQUTVVdo57nWTLt_ea2UynGUpo"http://localhost:5276/secretHTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8Date: Mon, 04 Dec 2023 05:03:50 GMTServer: KestrelTransfer-Encoding: chunked

Hello admin. My secret


评论