管理杂谈OA答疑ERP答疑教程搜索

C# ASP.NET Core 前后端分离终极实战:JWT 身份认证与授权全攻略(保姆级配置 + 避坑指南)


在前后端分离成为主流的今天,传统的 Session/Cookie 认证已经力不从心 —— 跨域、分布式、移动端适配全是痛点。而JWT(JSON Web Token) 就是解决这些问题的「万能钥匙」!
今天这篇专栏,我会手把手带你完成ASP.NET Core JWT 认证完整配置,从 Nuget 引用、代码编写到高频踩坑全解析,用生活类比让你秒懂,新手也能直接 CV 跑通!

一、先搞懂:JWT 是什么?(生活类比 + 核心流程)

1. 生活类比:JWT = 景区电子门票

2. JWT 核心认证流程图

前端:用户输入账号密码

后端:验证账号密码正确性

验证通过?

返回错误:账号密码无效

后端生成JWT令牌,返回给前端

前端存储Token:LocalStorage/Cookie

前端请求接口:请求头携带Authorization: Bearer Token

后端:验证JWT令牌合法性/有效期

验证通过?

返回401:未授权

授权访问接口,返回数据

3. 核心价值

1.无状态:服务器不存储用户信息,分布式部署无压力;
2.跨域支持:完美适配前后端分离、小程序、APP;
3.安全可控:加密签名、过期时间、权限声明全自定义。

二、第一步:项目配置与 Nuget 包引用

1. 环境要求

2. 安装 Nuget 包(两种方式)

方式 1:Nuget 包管理器

VS 中右键项目 → 管理 Nuget 程序包 → 浏览 → 搜索**Microsoft.AspNetCore.Authentication.JwtBearer ** → 安装最新稳定版。

方式 2:程序包管理器控制台

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
方式 3:.NET CLI 命令
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

三、第二步:appsettings.json 配置 JWT 核心参数

我们把 JWT 的密钥、颁发者、过期时间等配置写在配置文件,方便后期修改。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  // JWT配置节点
  "JwtSettings": {
    "SecretKey": "LongLongSecretKey@1234567890ABCDEF", // 密钥:越长越安全,至少16位
    "Issuer": "MyBackendServer", // 令牌颁发者(你的后端服务)
    "Audience": "MyFrontendClient", // 令牌接收者(你的前端)
    "ExpiresMinutes": 60 // 令牌过期时间:60分钟
  },
  "AllowedHosts": "*"
}

✅ 小节重点

  1. SecretKey:绝对不能泄露!相当于你的令牌「签名钥匙」,泄露后任何人都能伪造令牌;
  2. ExpiresMinutes:不建议设置过长,建议 30~120 分钟,配合刷新 Token 使用;
    3.Issuer 和 Audience:前后端必须保持一致,否则验证失败。

四、第三步:Program.cs 注册 JWT 认证服务(核心代码)

这是 JWT 生效的核心步骤,我们需要在 Program.cs 中注册认证、授权服务,并启用中间件。
完整代码(.NET 6+ 顶级语句)

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// 1. 添加控制器服务
builder.Services.AddControllers();
// 2. 从配置文件读取JWT参数
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["SecretKey"];
var issuer = jwtSettings["Issuer"];
var audience = jwtSettings["Audience"];
var expiresMinutes = Convert.ToDouble(jwtSettings["ExpiresMinutes"]);
// 3. 注册JWT认证服务 ★核心代码★
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        // 配置令牌验证参数
        options.TokenValidationParameters = new TokenValidationParameters
        {
            // 验证颁发者
            ValidateIssuer = true,
            ValidIssuer = issuer,
            
            // 验证接收者
            ValidateAudience = true,
            ValidAudience = audience,
            
            // 验证过期时间
            ValidateLifetime = true,
            
            // 验证签名密钥
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
            
            // 过期时间容错值(防止服务器时间不同步)
            ClockSkew = TimeSpan.Zero
        };
        // 可选:配置JWT认证失败的自定义返回信息
        options.Events = new JwtBearerEvents
        {
            OnChallenge = context =>
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                context.Response.ContentType = "application/json";
                var result = new { code = 401, message = "未授权:请先登录获取Token" };
                context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(result));
                return Task.CompletedTask;
            }
        };
    });
// 4. 注册授权服务
builder.Services.AddAuthorization();
var app = builder.Build();
// 中间件执行顺序:必须是 认证 → 授权 → 路由
app.UseHttpsRedirection();
// ★ 顺序绝对不能错 ★
app.UseAuthentication(); // 启用认证(第一步)
app.UseAuthorization();  // 启用授权(第二步)
app.MapControllers();
app.Run();

✅ 小节重点

  1. 中间件顺序:UseAuthentication 必须在 UseAuthorization 之前!先认证身份,再判断权限;
  2. ClockSkew:设置为 0,严格校验过期时间,避免令牌超时仍能使用;
  3. 自定义 OnChallenge:让认证失败返回友好 JSON,而非默认的 HTML 页面。

五、第四步:编写 JWT 令牌生成工具类

我们封装一个通用工具类,用于用户登录成功后生成 JWT 令牌。


using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace JwtDemo.Utils
{
    /// <summary>
    /// JWT令牌生成工具类
    /// </summary>
    public static class JwtTokenHelper
    {
        /// <summary>
        /// 生成JWT Token
        /// </summary>
        /// <param name="configuration">配置文件</param>
        /// <param name="userId">用户ID</param>
        /// <param name="userName">用户名</param>
        /// <param name="role">用户角色(admin/user)</param>
        /// <returns>JWT令牌</returns>
        public static string CreateToken(IConfiguration configuration, string userId, string userName, string role)
        {
            // 读取JWT配置
            var jwtSettings = configuration.GetSection("JwtSettings");
            var secretKey = jwtSettings["SecretKey"];
            var issuer = jwtSettings["Issuer"];
            var audience = jwtSettings["Audience"];
            var expiresMinutes = Convert.ToDouble(jwtSettings["ExpiresMinutes"]);
            // 1. 创建用户声明(存储用户信息,如ID、角色、权限)
            var claims = new[]
            {
                new Claim(ClaimTypes.NameIdentifier, userId), // 用户ID
                new Claim(ClaimTypes.Name, userName), // 用户名
                new Claim(ClaimTypes.Role, role), // 用户角色
                new Claim("CustomInfo", "自定义业务数据") // 自定义声明
            };
            // 2. 创建密钥对象
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            // 3. 创建签名凭证
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            // 4. 生成JWT令牌
            var token = new JwtSecurityToken(
                issuer: issuer,
                audience: audience,
                claims: claims,
                expires: DateTime.Now.AddMinutes(expiresMinutes), // 过期时间
                signingCredentials: credentials
            );
            // 5. 生成最终的Token字符串
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}

✅ 小节重点

  1. Claim(声明):存储在令牌里的用户信息,相当于门票上的「身份信息」;
  2. 角色声明:用于后续权限控制,必须用ClaimTypes.Role类型;
  3. 令牌加密:固定使用HmacSha256算法,安全性最高。

六、第五步:编写登录接口 + 受保护接口

1. 登录接口(无需认证,生成 Token)

using Microsoft.AspNetCore.Mvc;
using JwtDemo.Utils;
namespace JwtDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class LoginController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        // 注入配置文件
        public LoginController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        /// <summary>
        /// 用户登录:验证账号密码,生成JWT Token
        /// </summary>
        [HttpPost]
        public IActionResult Login(string userName, string password)
        {
            // 模拟数据库验证账号密码(实际项目替换为真实校验)
            if (userName == "admin" && password == "123456")
            {
                // 登录成功,生成Token
                var token = JwtTokenHelper.CreateToken(_configuration, "1001", userName, "admin");
                return Ok(new
                {
                    code = 200,
                    message = "登录成功",
                    token = token,
                    expiresIn = 60 // 过期时间(分钟)
                });
            }
            // 登录失败
            return Ok(new { code = 400, message = "账号或密码错误" });
        }
    }
}

2. 受保护接口(需要 JWT 认证才能访问)

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JwtDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    // 全局添加[Authorize]:整个控制器需要认证
    [Authorize]
    public class UserController : ControllerBase
    {
        /// <summary>
        /// 获取用户信息:必须携带有效Token才能访问
        /// </summary>
        [HttpGet("info")]
        public IActionResult GetUserInfo()
        {
            // 从JWT令牌中读取用户信息
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            var userName = User.Identity?.Name;
            var role = User.FindFirst(ClaimTypes.Role)?.Value;
            return Ok(new
            {
                code = 200,
                message = "获取用户信息成功",
                data = new { userId, userName, role }
            });
        }
        /// <summary>
        /// 仅管理员可访问:角色权限校验
        /// </summary>
        [HttpGet("admin")]
        [Authorize(Roles = "admin")]
        public IActionResult AdminApi()
        {
            return Ok(new { code = 200, message = "管理员接口访问成功" });
        }
    }
}

✅ 小节重点
1.[AllowAnonymous]:跳过认证,登录接口必须加;
2.[Authorize]:需要认证才能访问;
3.[Authorize(Roles = “admin”)]:角色授权,仅指定角色可访问。

七、高频踩坑大全(90% 的新手都栽过!)

1. 中间件顺序错误(最常见)

2. JWT 密钥太短 / 泄露

3. Issuer/Audience 前后端不一致

4. 令牌过期 / 服务器时间不同步

5. 前端请求头格式错误

6. 忘记注册认证服务

八、测试验证(Postman/Swagger)

1.运行项目,访问/api/Login,输入账号密码获取 Token;
2.访问/api/User/info,请求头添加Authorization: Bearer 你的Token;
3.验证结果:

📢 结尾互动
今天的 JWT 认证全套配置就讲完啦!从代码 CV 到避坑,新手也能直接落地前后端分离项目!
互动问题
你在项目中用的是 JWT 还是 Session 认证?
你还遇到过哪些 JWT 踩坑问题?评论区告诉我!

总结

1.JWT = 前后端分离必备认证方案,无状态、跨域、安全;
2.核心三步:安装 Nuget 包→注册认证服务→生成 / 验证令牌
3.避坑核心:中间件顺序、密钥安全、请求头格式三大关键点;
4.代码全量可直接 CV 运行,适合.NET6/7/8 所有版本!
转自https://blog.csdn.net/William_cl/article/details/159736029


更多精彩文章浏览...
点击右上角图标分享到朋友圈
官方网站:http://www.clicksun.cn
咨询热线:400-186-1886
服务邮箱:service@clicksun.cn