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 认证和授权有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1194504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

依赖版本打架怎么办?5个真实案例带你实战解决Maven冲突难题

第一章&#xff1a;依赖版本打架怎么办&#xff1f;5个真实案例带你实战解决Maven冲突难题 在实际开发中&#xff0c;Maven依赖冲突是Java项目常见的“隐性故障源”。不同库引入同一依赖的不同版本时&#xff0c;可能导致类找不到、方法不存在甚至运行时异常。通过分析和解决真…

Java Debug效率革命?飞算JavaAI一键修复器全面评测

Java开发过程中&#xff0c;Bug排查始终是影响开发效率的核心痛点。无论是新手面对控制台冗长报错日志的手足无措&#xff0c;还是资深开发者花费数小时排查隐藏的逻辑漏洞、依赖冲突&#xff0c;甚至是简单的语法疏漏&#xff0c;都在无形中消耗着开发人员的时间与精力。为验证…

如何在30分钟内完成Spring Boot 3与MyBatis-Plus的无缝对接?真相在这里

第一章&#xff1a;Spring Boot 3与MyBatis-Plus整合概述在现代Java后端开发中&#xff0c;Spring Boot 3以其自动配置、起步依赖和响应式编程支持等特性&#xff0c;成为构建微服务架构的首选框架。与此同时&#xff0c;MyBatis-Plus作为MyBatis的增强工具&#xff0c;在简化C…

单例被破坏?Spring Bean不是单例?——深入JVM类加载、反射、反序列化场景下的5大失效真相

第一章&#xff1a;单例模式的核心概念与设计哲学 单例模式&#xff08;Singleton Pattern&#xff09;是创建型设计模式中最基础且广泛应用的一种&#xff0c;其核心目标是确保一个类在整个应用程序生命周期中仅存在一个实例&#xff0c;并提供一个全局访问点。这种设计不仅节…

8.1 拒绝两眼一抹黑:日志、监控、告警三位一体的可观测性方法论

8.1 拒绝两眼一抹黑:日志、监控、告警三位一体的可观测性方法论 1. 引言:可观测性的三个支柱 在云原生时代,系统复杂度呈指数级增长。当生产环境出现问题时,如果缺乏可观测性,你就像在黑暗中摸索。 可观测性(Observability) 不是监控(Monitoring)的升级版,而是一个…

零售行业OCR应用案例:商品标签识别系统搭建全过程

零售行业OCR应用案例&#xff1a;商品标签识别系统搭建全过程 在零售行业&#xff0c;每天都有大量的商品需要录入系统、核对信息、更新库存。传统的人工录入方式不仅效率低&#xff0c;还容易出错。有没有一种方法&#xff0c;能快速准确地从商品标签上提取文字信息&#xff…

【企业级Excel导出黄金标准】:从5分钟到8秒——基于EasyExcel 3.0+自研缓冲池的千万级导出压测实录

第一章&#xff1a;企业级Excel导出性能瓶颈的根源诊断 在大型企业系统中&#xff0c;批量导出海量数据至Excel文件是常见需求&#xff0c;但随着数据量增长&#xff0c;导出操作常出现响应缓慢、内存溢出甚至服务崩溃等问题。这些问题背后往往隐藏着深层次的技术瓶颈&#xff…

Maven依赖冲突怎么破?资深工程师教你7种高效排查与隔离手段

第一章&#xff1a;Maven依赖冲突的本质与常见场景 在Maven项目构建过程中&#xff0c;依赖冲突是开发者频繁遭遇的问题之一。其本质源于Maven的“传递性依赖”机制与“最近路径优先”&#xff08;Nearest-First&#xff09;的依赖解析策略之间的交互。当多个路径引入同一依赖的…

3种高效Selenium登录方案曝光:自动点击不再被反爬拦截

第一章&#xff1a;Selenium模拟登录的核心挑战在自动化测试和数据采集场景中&#xff0c;Selenium 因其强大的浏览器操控能力成为模拟用户登录的首选工具。然而&#xff0c;实际应用中会面临诸多技术障碍&#xff0c;直接影响脚本的稳定性与成功率。动态内容加载 现代网页广泛…

JNI简单学习(java调用C/C++) - 实践

JNI简单学习(java调用C/C++) - 实践2026-01-21 12:21 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !i…

Java导出Excel慢如蜗牛?3个被忽略的JVM参数+2种零拷贝写入法,立竿见影提速17倍

第一章&#xff1a;Java导出百万级数据到Excel的性能挑战 在企业级应用中&#xff0c;将大量数据导出为 Excel 文件是常见的需求。然而&#xff0c;当数据量达到百万级别时&#xff0c;传统的导出方式往往会面临严重的性能瓶颈。Java 常用的 Apache POI 库虽然功能强大&#xf…

建议收藏】大模型推理技术详解:从显存管理到算法加速的全景指南

本文系统解析大模型推理技术的演进与优化&#xff0c;涵盖显存管理&#xff08;PagedAttention、分层KV缓存&#xff09;、注意力计算优化&#xff08;FlashAttention系列&#xff09;、调度与批处理&#xff08;PD分离架构&#xff09;、并行策略与MoE优化、算法加速&#xff…

2026皮带上料机选购指南:热门企业产品性能大比拼,传动链条/乙型网带/非标链条/料斗提升机,上料机公司怎么选择

在工业自动化生产中,皮带上料机作为物料输送的核心设备,直接影响着生产线效率与产品质量。尤其在玻璃、食品加工等高精度行业,其稳定性、耐久性及适配性成为保障安全生产、改善作业环境的关键因素。然而,当前市场上…

【资深架构师亲授】CORS跨域配置最佳实践,企业级项目都在用

第一章&#xff1a;CORS跨域问题的本质与Java解决方案概述 CORS&#xff08;Cross-Origin Resource Sharing&#xff09;是浏览器为保障网络安全而实施的一种同源策略机制。当一个资源试图从不同于其自身源&#xff08;协议、域名、端口任一不同即视为跨域&#xff09;的服务器…

大模型入门必收藏!一文看懂AI、机器学习、深度学习、LLM和Agent的关系

文章通过金字塔比喻&#xff0c;清晰解析了AI相关概念的层次关系&#xff1a;AI是顶层目标&#xff0c;机器学习是实现方法&#xff0c;深度学习是核心技术&#xff0c;大模型是规模化的深度学习产物&#xff0c;LLM是专门处理语言的大模型代表&#xff0c;Agent则是将大模型能…

C#进阶疗法 -- 拦截器

代码拦截器入门指南&#xff1a;使用 Castle.DynamicProxy 实现方法拦截 什么是代码拦截器&#xff1f; 代码拦截器是一种设计模式&#xff0c;允许我们在不修改原有代码的情况下&#xff0c;在方法执行前后插入自定义逻辑。这种技术在很多场景下非常有用&#xff0c;属于aop编…

浙江正规的胶辊包胶供应商有哪些,泰兴金茂辊业特色显著

在工业生产领域,胶辊作为关键传动与加工部件,其性能直接影响生产线效率与产品质量。当胶辊出现磨损、老化或脱胶问题时,选择靠谱的旧胶辊包胶厂家、靠谱的胶辊包胶翻新供应商及正规的胶辊包胶供应商,成为企业降低成…

揭秘Java CORS跨域难题:5步快速配置,彻底解决前后端分离痛点

第一章&#xff1a;Java CORS跨域难题的本质解析CORS&#xff08;Cross-Origin Resource Sharing&#xff09;是浏览器实现的一种安全机制&#xff0c;用于限制不同源之间的资源请求。当Java后端服务与前端应用部署在不同域名或端口时&#xff0c;浏览器会发起预检请求&#xf…

Spring Cloud Gateway鉴权过滤器深度剖析(架构师私藏笔记曝光)

第一章&#xff1a;Spring Cloud Gateway鉴权过滤器核心概念解析 在微服务架构中&#xff0c;API网关作为系统的统一入口&#xff0c;承担着请求路由、限流、监控和安全控制等关键职责。Spring Cloud Gateway 作为 Spring 官方推出的响应式网关框架&#xff0c;提供了强大的过滤…

国产化替代中WordPress如何兼容信创环境公式编辑?

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