我有一个问题,当用户登录并在响应中发送他的JWT令牌时,当他试图访问授权端点时,它总是返回401。我不知道为什么即使他有JWT,他也没有通过身份验证?
这是程序.cs代码:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using ProuductsShopWepAPI.Models;
using ProuductsShopWepAPI.Reopositories;
using ProuductsShopWepAPI.RepositoriesContracts;
using ProuductsShopWepAPI.Services;
using ProuductsShopWepAPI.ServicesContracts;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please enter a valid token",
Name = "Authorization",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
Scheme = "Bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type=ReferenceType.SecurityScheme,
Id="Bearer"
}
},
Array.Empty<string>()
}
});
});
// Add Api services
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<ICategoryRepository, CategoryRepository>();
builder.Services.AddScoped<IAccountService, AccountService>();
// Configure Entity frame work
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("Default"));
});
// Configure jwt authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidateAudience = true,
ValidAudience = builder.Configuration["JWT:Audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"])),
};
});
//Configure Identity
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
options.Password.RequiredUniqueChars = 5;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequiredLength = 8;
options.Password.RequireUppercase = true;
}).AddEntityFrameworkStores<ApplicationDbContext>();
//Configure CORS
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyHeader();
policy.AllowAnyMethod();
policy.AllowAnyOrigin();
});
});
builder.Services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToAccessDenied =
options.Events.OnRedirectToLogin = (context) =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.FromResult<object>(null);
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors();
app.UseResponseCaching();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
这是生成JWT令牌的代码:
public async Task<JwtSecurityToken> CreateJwtAsync(LoginDTO loginDTO)
{
var user = new IdentityUser()
{
Email = loginDTO.Email
};
var issuer = _configuration["JWT:Issuer"];
var audience = _configuration["JWT:Audience"];
var key = _configuration["JWT:key"];
var signingCredintials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)), SecurityAlgorithms.HmacSha256);
var roles = await _userManager.GetRolesAsync(user);
var claims = await _userManager.GetClaimsAsync(user) ?? new List<Claim>();
foreach (var role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
claims.Add(new Claim(ClaimTypes.Name, loginDTO.Email));
var jwtObject = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.UtcNow.AddSeconds(1000),
signingCredentials: signingCredintials
);
return jwtObject;
}
登录终结点:
[HttpPost]
public async Task<IActionResult> Login(LoginDTO loginDTO)
{
try
{
if (!ModelState.IsValid)
{
var details = new ValidationProblemDetails(ModelState);
details.Status = StatusCodes.Status400BadRequest;
return BadRequest(details);
}
var isLoginValid = await _accountService.IsLoginValidAsync(loginDTO);
if (!isLoginValid) throw new Exception("Email or password is not valid");
var jwtObject = await _accountService.CreateJwtAsync(loginDTO);
var stringJwt = new JwtSecurityTokenHandler().WriteToken(jwtObject);
HttpContext.Response.Headers["Authorization"] = stringJwt;
return StatusCode(StatusCodes.Status200OK, stringJwt);
}
catch (Exception ex)
{
var problemDetails = new ProblemDetails();
problemDetails.Detail = ex.Message;
problemDetails.Status = StatusCodes.Status400BadRequest;
return StatusCode(StatusCodes.Status400BadRequest, problemDetails);
}
}
这是种子/类别端点
[HttpPost]
[Authorize]
public async Task<IActionResult> Categories()
{
var newCategoriees = new List<Category>();
using (var reader = new StreamReader($"{_environment.ContentRootPath}/Data/amazon_categories.csv"))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
var dic = _categoryRepository.GetAll();
var dic1 = await dic.ToDictionaryAsync(c => c.Id);
var categories = csv.GetRecordsAsync<ProductCategorie>();
await foreach (var category in categories)
{
if (!dic1.ContainsKey(long.Parse(category.id)))
{
var newCategory = new Category();
newCategory.Id = long.Parse(category.id);
newCategory.Name = category.category_name;
newCategoriees.Add(newCategory);
}
}
}
}
await _categoryRepository.AddCategoriesAsync(newCategoriees);
return StatusCode(StatusCodes.Status200OK, $"{newCategoriees.Count} categories has been added");
}
正如您在这里看到的,即使用户在请求头中有授权,它也会返回401状态代码错误,而不是让他在数据库中播种类别
如果你知道如何解决这个问题,请告诉我。