Error 400 when using Anti Forgery Token in C# and Vue 3

45 Views Asked by At

I want to use anti-forgery-token for my login method in my C# and Vue 3 demo app but I always get error 400.I tried making a request to get the token,store it and put it in the headers but I am getting error 400.

Here is my Program.cs file here,I am not sure if I am correctly adding the token

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllers();
builder.Services.AddAntiforgery(option => option.HeaderName = "X-CSRF-TOKEN");

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add<AutoValidateAntiforgeryTokenAttribute>();
});


var app = builder.Build();


app.UseCors(o => o.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());

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

app.Urls.Add("http://localhost:5000");

app.Run();

This is my User Controller,here I made a new method to get the anti forgery token so I can get it with a request and use it in the headers

using Microsoft.AspNetCore.Mvc;
using System.Data.SqlClient;
using Dapper;
using WebApplication1.Models;
using Microsoft.AspNetCore.Antiforgery;
using NuGet.Common;

namespace userController.Controllers
{
    [ApiController]
    [Route("api")]
    public class UsersController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly IAntiforgery _antiforgery;

        public UsersController(IConfiguration configuration, IAntiforgery antiforgery)
        {
            _configuration = configuration;
            _antiforgery = antiforgery;
        }


        [HttpGet("get-anti-forgery-token")]
        public IActionResult GetAntiForgeryToken()
        {
            try
            {
                // Generate and store the anti-forgery token
                var tokens = _antiforgery.GetAndStoreTokens(HttpContext);

                // Return the anti-forgery token in the response
                return Ok(new { token = tokens.RequestToken });
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal Server Error: {ex.Message}");
            }
        }





        [HttpGet("users")]
        public IEnumerable<FormModel> GetUsers()
        {
            string connectionString = _configuration.GetConnectionString("DefaultConnection");

            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();

                string selectQuery = "SELECT * FROM Users";

                return connection.Query<FormModel>(selectQuery);
            }
        }


        [HttpPost("register")]
        public async Task<IActionResult> PostUser([FromBody] FormModel model)
        {
            try
            {
                string connectionString = _configuration.GetConnectionString("DefaultConnection");

                using (var connection = new SqlConnection(connectionString))
                {
                    await connection.OpenAsync();

                    // Check if the user with the same username already exists
                    string checkUserQuery = "SELECT COUNT(*) FROM Users WHERE Username = @Username";
                    int existingUser = await connection.QueryFirstOrDefaultAsync<int>(checkUserQuery, new { Username = model.Username });

                    if (existingUser > 0)
                    {
                        // User with the same username already exists, handle accordingly
                        return Conflict("Username already exists");
                    }

                    string insertQuery = "INSERT INTO Users (Username, Password) OUTPUT INSERTED.Id VALUES (@Username, @Password)";
                    int userId = await connection.QueryFirstOrDefaultAsync<int>(insertQuery, new { Username = model.Username, Password = model.Password });

                    model.Id = userId;
                    return Ok(model);
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal Server Error: {ex.Message}");
            }
        }


        [HttpGet("testredirect")]
        public IActionResult GetLoginInfo([FromQuery] FormModel model)
        {
            return Redirect("/api/login?username=" + model.Username + "&password=" + model.Password);
        }

        [ValidateAntiForgeryToken]
        [HttpPost("login")]
        public async Task<ActionResult<FormModel>> LoginUser([FromBody] FormModel model)

        {
            try
            {
                string connectionString = _configuration.GetConnectionString("DefaultConnection");

                using (var connection = new SqlConnection(connectionString))
                {
                    string selectQuery = "SELECT * FROM Users WHERE Username = @Username AND Password = @Password";
                    var user = await connection.QueryFirstOrDefaultAsync<FormModel>(selectQuery, new { Username = model.Username, Password = model.Password});

                    if (user != null)
                    {
                        return Ok(user);
                    }
                    else
                    {
                        // Return 401 Unauthorized
                        return Unauthorized();
                    }
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal Server Error: {ex.Message}");
            }
        }


        [HttpPut("update/{id}")]
        public async Task<IActionResult> UpdateUser([FromBody] FormModel model, int id)
        {
            try
            {
                string connectionString = _configuration.GetConnectionString("DefaultConnection");

                using (var connection = new SqlConnection(connectionString))
                {
                    await connection.OpenAsync();

                    string checkUserQuery = "SELECT COUNT(*) FROM Users WHERE Id = @Id";
                    var userCount = await connection.QueryFirstOrDefaultAsync<int>(checkUserQuery, new { Id = id });
                    if (userCount == 0)
                    {
                        // User with the given ID does not exist
                        return NotFound();
                    }

                    string updateQuery = "UPDATE Users SET Username = @Username WHERE Id = @Id";
                    await connection.ExecuteAsync(updateQuery, new { Id = id, Username = model.Username });

                    return Ok();
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal Server Error: {ex.Message}");
            }
        }


        [HttpDelete("delete/{id}")]
        public async Task<IActionResult> DeleteUser(int id)
        {
            try
            {
                string connectionString = _configuration.GetConnectionString("DefaultConnection");

                using (var connection = new SqlConnection(connectionString))
                {
                    string deleteQuery = "DELETE FROM Users WHERE Id = @Id;";
                    await connection.ExecuteAsync(deleteQuery, new { Id = id });

                    return Ok($"User with ID {id} has been deleted");
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal Server Error: {ex.Message}");
            }
        }
    }
}

Vue Template

<template>
  <div>
    <form v-if="!loggedIn" @submit.prevent="submitForm">
      <h1>Register</h1>
      <label for="username">Username:</label>
      <input v-model="username" type="text" id="username" required />

      <label for="password">Password:</label>
      <input v-model="password" type="password" id="password" required />

      <div v-if="usernameError !== ''">
        <p>{{ usernameError }}</p>
      </div>
      <button type="submit">Submit</button>
    </form>

    <form v-if="!loggedIn" @submit.prevent="login">
      <h1>login</h1>
      <label for="username">Username:</label>
      <input v-model="loginUsername" __RequestVerificationToken type="text" id="username" required />

      <label for="password">Password:</label>
      <input v-model="loginPassword" __RequestVerificationToken type="password" id="password" required />

      <button type="submit">Submit</button>
    </form>
    <div v-if="loggedIn">
      <p>Logged In as {{ loggedInUser.username }}</p>
      change username
      <input type="text" v-model="newUsername" />
      <button @click="editUser()"  :disabled="newUsername.trim() === ''" >Edit</button>
      <button @click="deleteUser()">Delete</button>
      <div v-if="updatedusername">
        <p>Successfully updated!</p>
      </div>
      <div v-if="sameUsername">
        <p>You cannot change your username to the same username</p>
      </div>
      <p>Add a book</p>
      <form @submit.prevent="addBook">
        <label for="bookTitle">Title:</label>
        <input type="text" id="bookTitle" v-model="bookTitle" />
        <label for="bookAuthor">Author:</label>
        <input type="text" id="bookAuthor" v-model="bookAuthor" />
        <button type="submit">Submit</button>
      </form>
      <div v-for="book in mybookCollection" :key="book.id">
        {{ book.title }} - {{ book.author }}
        <button @click="deleteBook(book.bookId)">Delete</button>
      </div>
    </div>
    <div v-if="loginError">
      <p>{{ loginError }}</p>
    </div>
    <div v-for="user in users" :key="user.id">{{ user.username }}
    <input type="checkbox" >
    </div>
  </div>
  <div v-if="loggedIn">
    <button @click="logout">Logout</button>
  </div>
</template>

Vue Script

<script setup>
import { ref, onMounted } from "vue";
import axios from "axios";

const username = ref("");
const password = ref("");
const loginUsername = ref("");
const loginPassword = ref("");
const usernameError = ref("");
const users = ref([]);
const loggedIn = ref(false);
const loggedInUser = ref(null);
const loginError = ref("");
const bookTitle = ref("");
const bookAuthor = ref("");
const mybookCollection = ref([]);
const fileInput = ref(null);
const sameUsername = ref(false);
const newUsername = ref("");
const updatedusername = ref(false);
const userIds = ref([]);
const url = "http://localhost:5000/";

const saveUserToLocalStorage = (user) => {
  localStorage.setItem("loggedInUser", JSON.stringify(user));
};

const loadUserFromLocalStorage = () => {
  const user = localStorage.getItem("loggedInUser");
  return user ? JSON.parse(user) : null;
};

const clearUserFromLocalStorage = () => {
  localStorage.removeItem("loggedInUser");
};

const submitForm = () => {
  axios
    .post(`${url}api/register`, {
      username: username.value,
      password: password.value,
    })
    .then((response) => {
      console.log(`${response.data} has been created`);
      saveUserToLocalStorage(response.data);
      loggedInUser.value = response.data;
      loggedIn.value = true;
      username.value = "";
      password.value = "";
    })
    .catch((error) => {
      if (
        error.response &&
        error.response.status === 409 &&
        error.response.data.includes("Username already exists")
      ) {
        console.log("Username already exists");
        usernameError.value = "Username already exists";
      } else {
        console.log(`Unexpected error: ${error}`);
      }
    });
};

const editUser = () => {
  const id = loggedInUser.value.id;
  axios
    .put(`${url}api/update/${id}`, { username: newUsername.value, password: loggedInUser.value.password,id:id })
    .then((response) => {
      if(newUsername.value === loggedInUser.value.username){
        sameUsername.value = true;
        return;
      }

      if (!newUsername.value) {
        return;
      }

      console.log(response.data);

      updatedusername.value = true;
      setTimeout(() => {
        updatedusername.value = false;
      }, 2000);
      loggedInUser.value.username = newUsername.value;

      saveUserToLocalStorage(loggedInUser.value);
      newUsername.value = "";
    })
    .catch((error) => {
      console.log(`Unexpected error: ${error}`);
    });
};

const getAntiForgeryToken = async () => {
  try {
    const response = await axios.get(`${url}api/get-anti-forgery-token`);
    return response.data.token;
  } catch (error) {
    console.log(`Unexpected error: ${error}`);
    throw error; // Re-throw the error to be caught by the calling function
  }
};  
const login = async () => {
  const token = await getAntiForgeryToken();
  console.log(`Anti-forgery token: ${token}`);
  axios.post(`${url}api/login`, {
    username: loginUsername.value,
    password: loginPassword.value,
    

  }, {
    headers: {
  "X-CSRF-TOKEN": token,
}
  })
  .then((response) => {
    loggedInUser.value = response.data;
    loggedIn.value = true;
    saveUserToLocalStorage(loggedInUser.value);
    console.log(`${loggedInUser.value} has logged in`);
    // Additional logic, if needed
  })
  .catch((error) => {
    console.error('Login error:', error);
  });
};


const logout = () => {
  loggedIn.value = false;
  loggedInUser.value = null;
  clearUserFromLocalStorage();
};

const deleteUser = () => {
  const id = loggedInUser.value.id;
  axios
    .delete(`${url}api/delete/${id}`)
    .then((response) => {
      console.log(response.data);
      // Additional logic if needed after successful deletion
      loggedIn.value = false;
      loggedInUser.value = null;
      clearUserFromLocalStorage();
    })
    .catch((error) => {
      console.log(`Unexpected error: ${error}`);
    });
};

const addBook = () => {
  const id = loggedInUser.value.id;
  axios
    .post(`${url}api/insertbook/${id}`, {
      title: bookTitle.value,
      author: bookAuthor.value,
      userId: id,
    })
    .then((response) => {
      console.log(response.data);
      myBooks();
      bookAuthor.value = "";
      bookTitle.value = "";
    })
    .catch((error) => {
      console.log(`Unexpected error: ${error}`);
    });
};

const myBooks = () => {
  const id = loggedInUser.value.id;
  axios
    .get(`${url}api/getbooks/${id}`)
    .then((response) => {
      console.log(response.data);
      mybookCollection.value = response.data;
    })
    .catch((error) => {
      console.log(`Unexpected error: ${error}`);
    });
};

const deleteBook = (id) => {
  axios
    .delete(`${url}api/deletebook/${id}`)
    .then((response) => {
      console.log(response.data);
      mybookCollection.value = mybookCollection.value.filter(book => book.bookId !== id);
    })
    .catch((error) => {
      console.log(`Unexpected error: ${error}`);
    });
};

onMounted(() => {
  const user = loadUserFromLocalStorage();
  if (user) {
    loggedInUser.value = user;
    loggedIn.value = true;
    myBooks();

  }


});



</script>
0

There are 0 best solutions below