'CORS issue with one POST request but not another

I've looked at a few other questions, and they aren't having quite the same problem I'm having. I have a server running at localhost:5001 and a Vue website running at localhost:8080. When I do a /inventory/login post request, I'm not getting any CORS issues, but when I do a /inventory/computers request, I'm getting the following

Access to XMLHttpRequest at 'https://localhost:5001/inventory/computers' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What am I doing wrong? Here's the relevant code.

Startup.cs:

public void ConfigureServices(IServiceCollection services) {
  var connection = Configuration.GetConnectionString("Inventory");
  services.AddDbContextPool<InventoryContext>(options => options.UseSqlServer(connection));
  services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
    options.RequireHttpsMetadata = false;
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters() {
      ValidateIssuer = true,
      ValidateAudience = true,
      ValidAudience = Configuration["Jwt:Audience"],
      ValidIssuer = Configuration["Jwt:Issuer"],
      IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
    };
  });

  services.AddCors(options => {
    options.AddPolicy("AllowSpecificOrigin", builder => {
      builder.WithOrigins("localhost")
            .AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod();
    });
  });
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
  if (env.IsDevelopment()) {
    app.UseDeveloperExceptionPage();
  }

  app.UseHttpsRedirection();

  app.UseRouting();

  app.UseAuthentication();

  app.UseAuthorization();

  app.UseCors();

  app.UseEndpoints(endpoints => {
    endpoints.MapControllers();
  });
}

}

LoginController:

[Route("inventory/[controller]")]
[ApiController]
[EnableCors("AllowSpecificOrigin")]
public class LoginController : ControllerBase {
public IConfiguration _configuration;
private readonly InventoryContext _context;

public LoginController(IConfiguration config, InventoryContext context) {
  _configuration = config;
  _context = context;
}

[HttpPost]
public async Task<IActionResult> Post(LoginRequest req) {
  if (req != null && req.Username != null && req.Password != null) {
    User user = await _context.Users.FirstOrDefaultAsync(u => u.Username == req.Username);

    if (user == null || !Crypto.VerifyHashedPassword(user.HashedPassword, req.Password)) {
      return BadRequest("Invalid username or password.");
    }

    var claims = new[] {
      new Claim(JwtRegisteredClaimNames.Sub, _configuration["Jwt:Subject"]),
      new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
      new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString()),
      new Claim("EmployeeID", user.EmployeeId.ToString()),
      new Claim("Username", user.Username),
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
    var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    var token = new JwtSecurityToken(_configuration["Jwt:Issuer"], _configuration["Jwt:Audience"], claims, expires: DateTime.UtcNow.AddDays(1), signingCredentials: signIn);
    return Ok(new JwtSecurityTokenHandler().WriteToken(token));
  }
  else {
    return BadRequest();
  }
}

ComputerController:

[Authorize]
  [Route("inventory/[controller]")]
  [ApiController]
  [EnableCors("AllowSpecificOrigin")]
  public class ComputersController : ControllerBase {
    private readonly InventoryContext _context;

    public ComputersController(InventoryContext context) {
        _context = context;
    }



    // POST: api/Computers
    // To protect from overposting attacks, enable the specific properties you want to bind to, for
    // more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
    [EnableCors("AllowSpecificOrigin")]
    [HttpPost]
    public async Task<ActionResult<Computer>> PostComputer(ComputerPostRequest req) {
      Item item = new Item("Computer");
      _context.Items.Add(item);
      await _context.SaveChangesAsync();

      Computer computer = new Computer(item.ItemId, req.SelectBankcardSerialNumber, req.ManufacturerSerialNumber, req.Model, req.Name, req.Value, req.EmployeeID, req.DateObtained);
      _context.Computers.Add(computer);

      if (!String.IsNullOrEmpty(req.Notes)) {
        Note note = new Note(computer.ComputerId, req.Notes, DateTime.Now);
        _context.Notes.Add(note);
      }

      await _context.SaveChangesAsync();

      return CreatedAtAction("GetComputer", new { id = computer.ComputerId }, computer);
    }

And the Vue code:

Login.vue

async login() {
      if (this.isEmpty(this.username) || this.isEmpty(this.password)) {
        this.incorrect = true;
        console.log("Something's wrong");
        return false;
      }
      try {
        let res = await axios.post('https://localhost:5001/inventory/login', {
          username: this.username,
          password: this.password
        });
        this.$root.$authToken = "Bearer " + res.data;
      } catch (error) {
        console.log(error);
      }
    }

Computers.vue:

async upload() {
      if (this.isEmpty(this.sbSerialNum) || this.isEmpty(this.mSerialNum) || this.isEmpty(this.compModel) || this.isEmpty(this.compName) ||
      this.value === 0.0 || this.empID === 0 || this.isEmpty(this.dateObtained) || this.isEmpty(this.notes)) {
        this.incorrect = true;
        console.log("Something's wrong");
        return false;
      }
      try {
        const options = {
          headers: {'Authorization': this.$root.$authToken}
        };
        let res = await axios.post('https://localhost:5001/inventory/computers', {
          SelectBankcardSerialNumber: this.sbSerialNum,
          ManufacturerSerialNumber: this.mSerialNum,
          Name: this.compName,
          Model: this.compModel,
          Value: this.value,
          EmployeeID: this.empID,
          DateObtained: this.dateObtained,
          Notes: this.notes
        }, options);
        this.computerAdded = res.data;
      } catch (error) {
        console.log(error);
      }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source