Asp.net 6 授权。我有能力向客户端发送 JWT,但是当我尝试访问我的端点时,我得到 401。非常困惑

Posted

技术标签:

【中文标题】Asp.net 6 授权。我有能力向客户端发送 JWT,但是当我尝试访问我的端点时,我得到 401。非常困惑【英文标题】:Asp.net 6 Authorization. I have the ability to send the client a JWT but when I try access my end points I get 401. Very Confused 【发布时间】:2022-01-17 09:40:07 【问题描述】:

我正在尝试使用登录时发送给用户的 JWT 令牌解锁我的端点(控制器)。目前,注册和登录工作正常,并且向用户发送了一个 JWT 令牌。但是,当我使用邮递员或我的移动应用程序将 JWT 发送到 API 时,我收到 401 Unauthorized 错误。我正在使用 Asp.net 6 Web API。我已经添加了我的身份验证控制器和我的 program.cs。我的 appsettings.json 以及颁发者和受众中都有我的 JWT 密钥。我确定我的错误在我的 program.cs 中

AuthController

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using VelocityNetAPI.Models;
using System.Security.Cryptography;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using VelocityNetAPI.Data;
using Microsoft.AspNetCore.Authorization;

namespace VelocityNetAPI.Controllers

    
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    
        public static User user = new User();
        private readonly IConfiguration configuration;
        private readonly VelocityNetAPIContext context;
        public AuthController(IConfiguration configuration, VelocityNetAPIContext context)
        
            this.configuration = configuration;
            this.context = context;
        

        [HttpPost("Register")]
        public async Task<ActionResult<User>> Register(UserDto request)
        
            CreatePasswordHash(request.Password, out byte[] passwordHash, out byte[] passwordSalt);
            user.Name = request.Username;
            user.PasswordHash = passwordHash;
            user.PasswordSalt = passwordSalt;
            user.Role = "User";
            context.User.Add(user);
            await context.SaveChangesAsync();
            return Ok(user);
        

        [HttpPost("Login")]
        public async Task<ActionResult<string>> Login(UserDto request)
        
            //search for user
            var user = context.User.FirstOrDefault(u => u.Name == request.Username);
            if (user == null)
            
                return BadRequest("User not found");
            
            if(!VerifyPasswordHash(request.Password, user.PasswordHash, user.PasswordSalt))
            
                return BadRequest("Wrong Password");
            
            string token = CreateToken(user);
            return Ok(token);
        


        private string CreateToken(User user)
        
            List<Claim> claims = new List<Claim>
            
                new Claim(ClaimTypes.Name, user.Name),
                new Claim(ClaimTypes.Role, user.Role),
            ;
            var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(configuration["Jwt:key"]));
            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512);

            var token = new JwtSecurityToken(
                claims: claims,
                expires: DateTime.Now.AddDays(1),
                signingCredentials: cred);

            var jwt = new JwtSecurityTokenHandler().WriteToken(token);
            return jwt;
        

        private void CreatePasswordHash(String password, out byte[] passwordHash, out byte[] passwordSalt)
        
            using (HMACSHA512 hmac = new HMACSHA512())
            
                passwordSalt = hmac.Key;
                passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
            
        

        private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
        
            using (HMACSHA512 hmac = new HMACSHA512(passwordSalt))
            
                var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
                return computedHash.SequenceEqual(passwordHash);
            
        
    

Program.cs

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using VelocityNetAPI.Data;
using Microsoft.IdentityModel.Tokens;
using System.Configuration;
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authorization;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<VelocityNetAPIContext>(options =>
    
    options.UseSqlServer(builder.Configuration.GetConnectionString("VelocityNetAPIContext")));
var conf = builder.Configuration;
builder.Services.AddAuthentication(options =>

    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(x =>

    x.RequireHttpsMetadata = true;
    x.SaveToken = true;
    x.TokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = conf["Jwt:Issuer"].ToString(),
        ValidAudience = conf["Jwt:Audience"].ToString(),
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(conf["Jwt:Key"]))
    ;
);

//Configuration.GetSection("AppSettings:Token").Value)

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())

    app.UseSwagger();
    app.UseSwaggerUI();


app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

如果您需要更多信息,请告诉我 祝大家好运

【问题讨论】:

嗨@Riley-Howley,您将ValidateIssuerValidateAudience 设置为true。但是在您的 CreateToken 方法中,您不使用 Issuer 和 Audience 来创建令牌。所以一个简单的方法就是把ValidateIssuerValidateAudience 改成false。 嘿丽娜!非常感谢您的回复。按照您的建议,我已将 Issuer 和 Audience 都更改为 false。我在这个领域很迷茫哈哈。但是我仍然收到 401 错误。我确定我错过了一些东西,但不确定它可能是什么。当我实现您的更改并运行我的代码时,我很兴奋,然后意识到 Allow Anonymous 被设置为 Get 函数。谢谢你,但希望我能得到一个解决方案。 【参考方案1】:

您将ValidateIssuerValidateAudience 设置为true。但是在您的CreateToken 方法中,您不使用IssuerAudience 来生成令牌。

您可以更改您的CreateToken 方法,如下所示:

var token = new JwtSecurityToken(configuration["Jwt:Issuer"],
    configuration["Jwt:Audience"],
    claims: claims,
            expires: DateTime.Now.AddDays(1),
            signingCredentials: cred);

【讨论】:

将发行者和受众添加到令牌有效。非常感谢!

以上是关于Asp.net 6 授权。我有能力向客户端发送 JWT,但是当我尝试访问我的端点时,我得到 401。非常困惑的主要内容,如果未能解决你的问题,请参考以下文章

通过 ASP.NET 向用户发送 Excel

ASP.NET Core 在授权失败时发送 Access-Control-Allow-Origin 标头

从控制器事件(无客户端请求)向视图发送数据 ASP.NET MVC 4

通过js向授权的asp.net web api请求XLSX文件

ASP.NET Core Angular - 根据登录用户发送不同的 SignalR 消息

每当我发送包含 Bearer 令牌的请求时,ASP.Net Core API 总是返回 401 未授权