Mr_ALong 2023-04-07 22:18 采纳率: 77.8%
浏览 20
已结题

.Net 5 JWT 请求总是401

今天尝试 jwt 验证签名,总是报401,百思不得其解

这是创建token 方法

public static string GenerateJwt(IEnumerable<string> userRoles, JwtTokenPayload payload)
        {
            var claims = new List<Claim>
            {
                new Claim(JwtClaimKey.UserId, payload.UserId),
                new Claim(JwtClaimKey.UserName, payload.UserName),
                 new Claim(JwtRegisteredClaimNames.Iss,Iss),
                new Claim(JwtRegisteredClaimNames.Aud,Aud),
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddHours(2)).ToUnixTimeSeconds()}"),
            };

            // 可以将一个用户的多个角色全部赋予,比如参数System,Admin,那么该token即拥有两个角色
            claims.AddRange(userRoles.Select(role => new Claim(ClaimTypes.Role, role)));

            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: Iss,
                audience: Aud,
                claims: claims,
                expires: DateTime.Now.AddHours(Expire),
                signingCredentials: credentials);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

注册授权

services.AddAuthentication(options =>
            {
                // 设置默认使用jwt验证方式
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                // 添加JwtBearer服务
                .AddJwtBearer(o =>
                {
                    // token验证参数
                    o.TokenValidationParameters = new TokenValidationParameters
                    {
                        // 验证秘钥
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SetAppConfig.SecretKey)),
                        // 验证颁发者
                        ValidateIssuer = true,
                        ValidIssuer = SetAppConfig.Issuer,
                        // 验证订阅者
                        ValidateAudience = true,
                        ValidAudience = SetAppConfig.Audience,
                        ////验证令牌过期时间
                        ValidateLifetime = true,
                        // 验证过期时间必须设置该属性
                        ClockSkew = TimeSpan.FromDays(1)
                    };

                    // 默认有www-authenticate响应头提示验证失败信息
                });

            // 如果需要角色控制到Action则需要配置Policy
            // 如果没有配置AddPolicy,接口直接使用[Authorize]特性即可
            // 如果接口只允许Admin或System角色的Token访问,则需要添加了[Authorize("SystemOrAdmin")]特性
            // 详细请测试LoginController的ParseToken的方法
            services.AddAuthorization(options =>
            {
                //自定义策略(用于角色路径验证)
                //options.AddPolicy("Permission", policy => policy.Requirements.Add(new PolicyRequirement()));
                options.AddPolicy("User", policy => policy.RequireRole("User"));
                //options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
            });

然后是在ConfigureServices中 添加 AddSwaggerGen方法中与swaager绑定

s.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey,
                    Scheme = "bearer"
                });
                //声明一个Scheme,注意下面的Id要和上面AddSecurityDefinition中的参数name一致
                var scheme = new OpenApiSecurityScheme()
                {
                    Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
                };
                //注册全局认证(所有的接口都可以使用认证)
                s.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    [scheme] = new string[0]
                });

看了别人的一些思路

1.验证token是否正确

img

2.配置的顺序也没没问题啊

img

  • 写回答

2条回答 默认 最新

  • 港湾泊 2023-05-02 14:20
    关注

    你提供的代码初步来看是没有问题的,你可以考虑是其他的原因:

    1. 确保用于生成令牌的 SecretKey 与 TokenValidationParameters 中用于验证的密钥相同。 密钥可能已更改,导致验证失败。
    2. 检查令牌是否以正确的格式传递。 令牌应在 HTTP 请求的授权标头中传递,前缀为 Bearer(末尾有一个空格),后跟令牌字符串。
    3. 验证 TokenValidationParameters 中的 ValidateIssuer、ValidateAudience 和 ValidateLifetime 选项是否设置为 true。 这确保令牌针对正确的发行者和受众进行验证,并且它没有过期。
    4. 检查服务器和客户端计算机之间的时间同步。 如果两台机器上的时钟时间不同,可能会导致令牌因时钟偏差而被拒绝。

    如果您添加了授权策略,请确保在调用的操作方法中满足策略要求。 如果用户没有所需的角色或声明,令牌将被拒绝。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 7月4日
  • 已采纳回答 6月26日
  • 创建了问题 4月7日

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看