You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JWT实现React到ASP.NET Core Web API的用户授权及Bearer令牌使用

问题解答

核心疑问答复

  • 关于请求是否需要每次携带Bearer令牌:所有需要授权访问的接口(登录、公开帖子列表等公开接口除外)都需要在请求头携带Authorization: Bearer 令牌,JWT本身是无状态认证机制,后端不存储用户会话信息,只能通过每次请求携带的令牌识别用户身份。
  • 关于后端是否需要每次校验令牌:必须每次校验,防止令牌伪造、篡改、过期后被恶意使用,ASP.NET Core已提供开箱即用的JWT校验中间件,无需手动在每个接口写校验逻辑。

优化方案

1. 后端改造(移除多余接口,用官方认证中间件)

第一步:配置JWT认证中间件

在.NET 6+的Program.cs中添加如下配置(旧版Startup.cs对应放到ConfigureServices和Configure方法中):

// 加到var builder = WebApplication.CreateBuilder(args);之后
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        var jwtConfig = builder.Configuration.GetSection("JwtTokenConfig").Get<JwtTokenConfig>();
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true, // 必须开启令牌有效期校验
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtConfig.Issuer,
            ValidAudience = jwtConfig.Audience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.Secret)),
            // 允许的服务器时间偏移
            ClockSkew = TimeSpan.FromSeconds(30)
        };
    });

// 加到var app = builder.Build();之后,app.MapControllers()之前
app.UseAuthentication();
app.UseAuthorization();

第二步:改造业务接口

给需要授权的接口添加[Authorize]特性,直接从上下文获取用户ID,无需前端传参:

[HttpPost("create")]
[Authorize] // 加了这个特性,请求必须带有效JWT才能访问
public async Task<IActionResult> CreateComment([FromBody] CreateCommentDto dto)
{
    // 直接从当前用户Claims拿ID,不需要前端传UserId
    var userId = User.FindFirstValue("id");
    var comment = new Comment
    {
        Content = dto.Content,
        PostId = dto.PostId,
        UserId = userId
    };
    // 保存到数据库逻辑
    return Ok();
}

// 对应CreateCommentDto定义
public class CreateCommentDto
{
    public string Content { get; set; }
    public int PostId { get; set; }
}

你原来的/api/AppUsers/user接口完全可以删除,不需要再使用。

2. 前端改造(移除多余请求,自动加认证头)

第一步:封装通用请求工具

新建request.js,自动携带JWT令牌:

const baseUrl = 'https://localhost:44366/api';

export default async function request(url, options = {}) {
  const jwt = localStorage.getItem('jwt');
  const headers = {
    'Content-Type': 'application/json',
    ...options.headers
  };
  // 有令牌就自动加Authorization头
  if (jwt) {
    headers['Authorization'] = `Bearer ${jwt}`;
  }
  const response = await fetch(`${baseUrl}/${url}`, {
    ...options,
    headers,
    credentials: 'include'
  });
  return response.json();
}

第二步:改造评论提交逻辑

删除多余的获取用户ID请求,直接提交评论:

const submitComment = async (e, postId) => {
  e.preventDefault();
  const data = {
    Content: text,
    PostId: postId
  };
  // 用封装的request方法,自动带认证头
  await request('Comments/create', {
    method: 'POST',
    body: JSON.stringify(data)
  }).catch(err => console.error('Error:', err));
  setText('');
}

注意事项

  • 你当前写的GetPrincipalFromToken方法中关闭了ValidateLifetime,仅在刷新令牌的场景下可以这么用,正常接口校验必须开启有效期,防止过期令牌被滥用。
  • 建议补充令牌过期刷新逻辑:当接口返回401状态码时,调用刷新令牌接口拿新的Access Token,重试原请求,避免用户频繁重新登录。
  • JWT存储在localStorage存在XSS攻击风险,高安全要求的场景可以改为存储在带HttpOnly属性的Cookie中。

内容的提问来源于stack exchange,提问作者Kristiyann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 01:15:04