news 2026/2/25 14:21:56

c#进阶疗法 -jwt+授权

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
c#进阶疗法 -jwt+授权

ASP.NET Core JWT 认证与授权实战指南

什么是 JWT?

JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT 可以被验证和信任,因为它是数字签名的。

JWT 通常由三部分组成,用点(.)分隔:

  1. 头部(Header):包含令牌的类型和使用的签名算法。
  2. 载荷(Payload):包含声明(claims),如用户 ID、角色等。
  3. 签名(Signature):用于验证令牌的完整性。

一个典型的 JWT 看起来像这样:

example.jwt.io

为什么需要 JWT?

在传统的认证系统中,服务器通常会在会话中存储用户信息,并向客户端发送一个会话 ID。客户端在后续的请求中使用这个会话 ID 来标识自己。这种方式有以下缺点:

  1. 服务器端存储:服务器需要存储会话信息,这会增加服务器的负担。
  2. 水平扩展困难:如果应用程序部署在多个服务器上,需要在服务器之间共享会话信息,这会增加系统的复杂性。
  3. 跨域问题:在跨域请求中,会话 cookie 可能会被阻止。

JWT 解决了这些问题,因为:

  1. 无状态:JWT 包含了所有必要的信息,服务器不需要存储会话信息。
  2. 易于水平扩展:由于服务器不需要存储会话信息,应用程序可以轻松地部署在多个服务器上。
  3. 跨域友好:JWT 可以通过 HTTP 头在不同域之间传递。

如何使用 JWT 实现认证和授权?

在 ASP.NET Core 中,我们可以使用Microsoft.AspNetCore.Authentication.JwtBearer包来实现 JWT 认证和授权。下面我们将通过具体的示例来演示如何使用 JWT 实现认证和授权。

步骤 1:安装必要的包

首先,我们需要在项目中安装必要的包:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt dotnet add package Microsoft.Extensions.Options

步骤 2:创建 JWT 相关类

2.1 创建 JwtSettings 类

首先,我们创建一个JwtSettings类,用于存储 JWT 的配置选项:

namespaceFrameLearning.BasicComponents.Jwt{publicclassJwtSettings{publicstringSecret{get;set;}publicstringIssuer{get;set;}publicstringAudience{get;set;}publicintExpirationInMinutes{get;set;}}}

在这个示例中,我们创建了一个JwtSettings类,它包含SecretIssuerAudienceExpirationInMinutes四个属性,用于存储 JWT 的密钥、颁发者、受众和过期时间。

2.2 创建 UserCredentials 类

接下来,我们创建一个UserCredentials类,用于存储登录请求的数据:

namespaceFrameLearning.BasicComponents.Jwt{publicclassUserCredentials{publicstringUsername{get;set;}publicstringPassword{get;set;}}}

在这个示例中,我们创建了一个UserCredentials类,它包含UsernamePassword两个属性,用于存储用户的用户名和密码。

2.3 创建 UserResponse 类

然后,我们创建一个UserResponse类,用于存储登录响应的数据:

namespaceFrameLearning.BasicComponents.Jwt{publicclassUserResponse{publicstringUsername{get;set;}publicstringToken{get;set;}publicList<string>Roles{get;set;}}}

在这个示例中,我们创建了一个UserResponse类,它包含UsernameTokenRoles三个属性,用于存储用户的用户名、JWT 令牌和角色。

2.4 创建 IJwtService 接口和 JwtService 类

最后,我们创建一个IJwtService接口和JwtService类,用于生成和验证 JWT 令牌:

usingMicrosoft.Extensions.Options;usingMicrosoft.IdentityModel.Tokens;usingSystem.IdentityModel.Tokens.Jwt;usingSystem.Security.Claims;usingSystem.Text;namespaceFrameLearning.BasicComponents.Jwt{publicinterfaceIJwtService{stringGenerateToken(stringusername,List<string>roles);ClaimsPrincipalValidateToken(stringtoken);}publicclassJwtService:IJwtService{privatereadonlyJwtSettings_jwtSettings;publicJwtService(IOptions<JwtSettings>jwtSettings){_jwtSettings=jwtSettings.Value;}publicstringGenerateToken(stringusername,List<string>roles){// 验证 JwtSettings 的属性是否为 nullif(string.IsNullOrEmpty(_jwtSettings.Secret)){thrownewException("JwtSettings.Secret 不能为空");}if(string.IsNullOrEmpty(_jwtSettings.Issuer)){thrownewException("JwtSettings.Issuer 不能为空");}if(string.IsNullOrEmpty(_jwtSettings.Audience)){thrownewException("JwtSettings.Audience 不能为空");}if(_jwtSettings.ExpirationInMinutes<=0){_jwtSettings.ExpirationInMinutes=30;// 默认 30 分钟}varclaims=newList<Claim>{newClaim(ClaimTypes.Name,username),newClaim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())};// 添加角色声明foreach(varroleinroles){claims.Add(newClaim(ClaimTypes.Role,role));}varkey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));varcreds=newSigningCredentials(key,SecurityAlgorithms.HmacSha256);vartoken=newJwtSecurityToken(issuer:_jwtSettings.Issuer,audience:_jwtSettings.Audience,claims:claims,expires:DateTime.Now.AddMinutes(_jwtSettings.ExpirationInMinutes),signingCredentials:creds);returnnewJwtSecurityTokenHandler().WriteToken(token);}publicClaimsPrincipalValidateToken(stringtoken){vartokenHandler=newJwtSecurityTokenHandler();varkey=Encoding.UTF8.GetBytes(_jwtSettings.Secret);try{varprincipal=tokenHandler.ValidateToken(token,newTokenValidationParameters{ValidateIssuerSigningKey=true,IssuerSigningKey=newSymmetricSecurityKey(key),ValidateIssuer=true,ValidateAudience=true,ValidIssuer=_jwtSettings.Issuer,ValidAudience=_jwtSettings.Audience,ValidateLifetime=true,ClockSkew=TimeSpan.Zero},outSecurityTokenvalidatedToken);varjwtToken=(JwtSecurityToken)validatedToken;if(jwtToken.ValidTo<DateTime.UtcNow){thrownewSecurityTokenExpiredException("Token has expired");}returnprincipal;}catch{returnnull;}}}}

在这个示例中,我们创建了一个IJwtService接口,它定义了GenerateTokenValidateToken两个方法,用于生成和验证 JWT 令牌。然后,我们创建了一个JwtService类,它实现了IJwtService接口的方法。在GenerateToken方法中,我们首先验证JwtSettings的属性是否为 null,然后创建声明列表,添加角色声明,创建密钥和签名凭据,创建 JWT 令牌,最后返回令牌字符串。在ValidateToken方法中,我们首先创建令牌处理器和密钥,然后验证令牌,最后返回声明主体。

步骤 3:配置 JWT 认证和授权

Program.cs文件中,我们需要配置 JWT 认证和授权:

// 配置 JWTbuilder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));// 注册服务builder.Services.AddScoped<IJwtService,JwtService>();// 添加 JWT 认证和授权builder.Services.AddAuthentication(options=>{options.DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options=>{options.TokenValidationParameters=newTokenValidationParameters{ValidateIssuer=true,ValidateAudience=true,ValidateLifetime=true,ValidateIssuerSigningKey=true,ValidIssuer=builder.Configuration["JwtSettings:Issuer"],ValidAudience=builder.Configuration["JwtSettings:Audience"],IssuerSigningKey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSettings:Secret"]))};// 需要指定 JWT 角色映射关系options.TokenValidationParameters.RoleClaimType=ClaimTypes.Role;options.Events=newJwtBearerEvents{OnChallenge=asynccontext=>{// 跳过默认响应context.HandleResponse();context.Response.StatusCode=StatusCodes.Status401Unauthorized;context.Response.ContentType="application/json";ApiResponse<object>apiResponse=newApiResponse<object>();apiResponse.Code=401;apiResponse.Message=context.ErrorDescription??"提供的令牌无效";apiResponse.Data=null;apiResponse.Success=false;awaitcontext.Response.WriteAsync(JsonSerializer.Serialize(apiResponse));}};});builder.Services.AddAuthorization();

在这个示例中,我们首先配置JwtSettings,然后注册IJwtService服务,接着添加 JWT 认证和授权,最后注册授权服务。在添加 JWT 认证时,我们配置了令牌验证参数,包括验证颁发者、受众、过期时间和签名密钥,以及指定 JWT 角色映射关系。我们还配置了OnChallenge事件,用于自定义未授权响应。

步骤 4:添加登录端点

在控制器中,我们需要添加一个登录端点,用于生成和返回 JWT 令牌:

[HttpPost("login")][AllowAnonymous]publicIActionResultLogin([FromBody]UserCredentialscredentials){varroles=_userServer.GetRoles();// 生成tokenvartoken=_jwtService.GenerateToken(credentials.Username,roles);returnOk(newUserResponse{Username=credentials.Username,Token=token,Roles=roles});}

在这个示例中,我们添加了一个Login方法,它接受一个UserCredentials对象作为参数,然后获取用户角色,生成 JWT 令牌,最后返回一个UserResponse对象,包含用户名、令牌和角色。

步骤 5:添加授权保护的端点

在控制器中,我们可以添加一些需要授权才能访问的端点:

[HttpGet][Authorize(Roles="Admin")]publicIActionResultGet(){varforecasts=Enumerable.Range(1,5).Select(index=>newWeatherForecast{Date=DateOnly.FromDateTime(DateTime.Now.AddDays(index)),TemperatureC=Random.Shared.Next(-20,55),Summary=Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();returnOk(forecasts);}

在这个示例中,我们添加了一个Get方法,它使用[Authorize(Roles = "Admin")]特性标记,表明只有具有Admin角色的用户才能访问这个方法。

配置 JWT 设置

appsettings.json文件中,我们需要配置 JWT 设置:

{"JwtSettings":{"Secret":"X7gT$pL2@mKq9!vN5&sF8*oU4^jH6%zR","Issuer":"TestApi","Audience":"TestApiUsers","ExpirationInMinutes":60}}

在这个示例中,我们配置了 JWT 的密钥、颁发者、受众和过期时间。

测试 JWT 认证和授权

步骤 1:获取 JWT 令牌

首先,我们需要发送一个 POST 请求到登录端点,获取 JWT 令牌:

POST /weatherforecast/login Content-Type: application/json { "username": "John", "password": "126.com" }

响应应该类似于:

{"username":"John","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiSm9obiIsImp0aSI6ImI3MDExYjZlLTZhZTQtNDgxMS05MGFlLWQxMDBkNjA5M2JmOSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwiZXhwIjoxNzY4OTAwOTc4LCJpc3MiOiJUZXN0QXBpIiwiYXVkIjoiVGVzdEFwaVVzZXJzIn0.nggbL8AmiYEejRAFZzCX6Xhv5dAuNGfjy45hQ7d225o","roles":["Admin"]}

步骤 2:使用 JWT 令牌访问受保护的端点

然后,我们可以使用获取到的 JWT 令牌访问受保护的端点:

GET /weatherforecast Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiSm9obiIsImp0aSI6ImI3MDExYjZlLTZhZTQtNDgxMS05MGFlLWQxMDBkNjA5M2JmOSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwiZXhwIjoxNzY4OTAwOTc4LCJpc3MiOiJUZXN0QXBpIiwiYXVkIjoiVGVzdEFwaVVzZXJzIn0.nggbL8AmiYEejRAFZzCX6Xhv5dAuNGfjy45hQ7d225o

响应应该类似于:

[{"date":"2026-01-22","temperatureC":12,"temperatureF":53,"summary":"Mild"},{"date":"2026-01-23","temperatureC":23,"temperatureF":73,"summary":"Warm"},{"date":"2026-01-24","temperatureC":-5,"temperatureF":23,"summary":"Freezing"},{"date":"2026-01-25","temperatureC":34,"temperatureF":93,"summary":"Hot"},{"date":"2026-01-26","temperatureC":18,"temperatureF":64,"summary":"Balmy"}]

步骤 3:测试未授权访问

如果我们不提供 JWT 令牌或者提供的令牌无效,访问受保护的端点应该返回未授权响应:

GET /weatherforecast

响应应该类似于:

{"code":401,"success":false,"data":null,"message":"提供的令牌无效"}

JWT 和授权的最佳实践

1. 安全存储密钥

JWT 密钥应该安全存储,不应该硬编码在代码中或者存储在版本控制系统中。建议使用环境变量或者密钥管理服务来存储 JWT 密钥。

2. 设置合理的过期时间

JWT 令牌应该设置合理的过期时间,不宜过长也不宜过短。过长的过期时间会增加安全风险,过短的过期时间会影响用户体验。建议根据应用程序的具体需求设置过期时间,通常为 15 分钟到 24 小时之间。

3. 使用 HTTPS

JWT 令牌应该通过 HTTPS 传输,以防止中间人攻击。

4. 验证令牌

在服务器端,每次收到 JWT 令牌时都应该验证令牌的有效性,包括验证签名、过期时间和声明。

5. 实现令牌刷新机制

为了避免用户频繁登录,建议实现令牌刷新机制,允许用户使用过期的令牌换取新的令牌。

6. 限制令牌的使用范围

JWT 令牌应该限制使用范围,只允许访问必要的资源。可以通过在令牌中添加scope声明来实现。

7. 监控和审计

应该监控和审计 JWT 令牌的使用情况,及时发现和处理异常情况。

总结

JWT 是一种基于 JSON 的开放标准,用于在各方之间安全地传输信息。在 ASP.NET Core 中,我们可以使用Microsoft.AspNetCore.Authentication.JwtBearer包来实现 JWT 认证和授权。

通过本文的示例,我们学习了如何:

  1. 创建 JWT 相关类,包括JwtSettingsUserCredentialsUserResponseIJwtServiceJwtService
  2. 配置 JWT 认证和授权。
  3. 添加登录端点,用于生成和返回 JWT 令牌。
  4. 添加授权保护的端点,需要授权才能访问。
  5. 配置 JWT 设置。
  6. 测试 JWT 认证和授权。

我们还学习了 JWT 和授权的最佳实践,包括安全存储密钥、设置合理的过期时间、使用 HTTPS、验证令牌、实现令牌刷新机制、限制令牌的使用范围,以及监控和审计。

希望本文对你理解和使用 ASP.NET Core JWT 认证和授权有所帮助!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/20 0:45:20

2026必备!专科生论文痛点TOP10 AI论文网站测评

2026必备&#xff01;专科生论文痛点TOP10 AI论文网站测评 2026年专科生论文写作工具深度测评 随着人工智能技术的不断进步&#xff0c;AI论文辅助工具已成为众多专科生提升写作效率、优化内容质量的重要帮手。然而&#xff0c;面对市场上琳琅满目的平台&#xff0c;如何选择…

作者头像 李华
网站建设 2026/2/23 3:12:15

【Web自动化进阶指南】:掌握Selenium模拟登录与元素精准点击

第一章&#xff1a;Web自动化进阶的核心价值 在现代软件开发与测试体系中&#xff0c;Web自动化已从基础的脚本录制迈向智能化、可维护性强的高级阶段。进阶的Web自动化不仅提升测试效率&#xff0c;更在持续集成/持续交付&#xff08;CI/CD&#xff09;流程中扮演关键角色&…

作者头像 李华
网站建设 2026/2/22 7:37:40

Face Fusion清空按钮失效?常见操作异常处理解决方案

Face Fusion清空按钮失效&#xff1f;常见操作异常处理解决方案 1. 问题背景与使用场景 你是不是也遇到过这种情况&#xff1a;在使用 Face Fusion WebUI 进行人脸融合时&#xff0c;点击「清空」按钮毫无反应&#xff0c;上传的图片、参数设置、结果预览全都卡在那里动不了&…

作者头像 李华
网站建设 2026/2/18 7:34:10

Vue.js vs React:全面对比

核心哲学差异方面Vue.jsReact设计理念渐进式框架声明式UI库核心思想"关爱开发者""拥抱函数式编程"学习曲线平缓&#xff0c;渐进式陡峭&#xff0c;概念较多模板 vs JSX模板为主JSX 为主1. 架构设计差异Vue - 渐进式框架<!-- Vue 2/3 模板语法 --> &…

作者头像 李华
网站建设 2026/2/25 10:14:07

网页编辑器如何优化WordPress的PPT公式远程协作功能?

要求&#xff1a;开源&#xff0c;免费&#xff0c;技术支持 博客&#xff1a;WordPress 开发语言&#xff1a;PHP 数据库&#xff1a;MySQL 功能&#xff1a;导入Word,导入Excel,导入PPT(PowerPoint),导入PDF,复制粘贴word,导入微信公众号内容,web截屏 平台&#xff1a;Window…

作者头像 李华
网站建设 2026/2/22 19:11:43

5.3 规模化管理:基于目录 vs 基于分支的多环境 多集群治理策略

5.3 规模化管理:基于目录 vs 基于分支的多环境/多集群治理策略 1. 引言:当应用数量从 10 到 100 单体应用迁到 K8s 尚可手工维护,微服务体量上来之后,环境维度(dev/staging/prod) 集群维度(多 Region/多租户/多云) 应用数量 会让任何脚本方案迅速失控。GitOps 的规模…

作者头像 李华