Create a React Login System with C# .NET API

To create a React login system that interacts with a C# .NET API, you’ll go through a series of steps involving both the frontend (React) and the backend (.NET Core API).

This example assumes you have a .NET Core API with an endpoint for authentication and a SQL Server database to store user credentials securely.

Step 1: Setting Up the .NET Core API

  1. Create the User Model

First, define a model for your users in the .NET Core API.

public class ApplicationUser
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string PasswordHash { get; set; }
}
  1. Create the Authentication Controller

Then, create a controller with an action to handle login requests.

[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly YourDbContext _context;
    private readonly IConfiguration _configuration;

    public AuthController(YourDbContext context, IConfiguration configuration)
    {
        _context = context;
        _configuration = configuration;
    }

    [HttpPost("login")]
    public async Task<ActionResult> Login([FromBody] LoginDto loginDto)
    {
        // Find the user by username
        var user = await _context.ApplicationUsers
                         .FirstOrDefaultAsync(u => u.Username == loginDto.Username);

        if (user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash))
        {
            return BadRequest("Username or password is incorrect");
        }

        // Generate a JWT token
        var token = GenerateJwtToken(user);

        return Ok(new { Token = token });
    }

    private string GenerateJwtToken(ApplicationUser user)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_configuration["JwtConfig:Secret"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Username)
            }),
            Expires = DateTime.UtcNow.AddDays(7),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}

Make sure you have BCrypt.Net installed for password hashing and comparison, and configure your JWT settings in appsettings.json.

  1. Configure JWT Authentication in Startup.cs

In Startup.cs, add JWT authentication to the ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    // Configure JWT authentication
    var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);
    services.AddAuthentication(x =>
    {
        x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(x =>
    {
        x.RequireHttpsMetadata = false;
        x.SaveToken = true;
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false
        };
    });

    // Add other services like DbContext
    // services.AddDbContext<YourDbContext>(options => ...);
}

And in the Configure method, enable authentication middleware.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Other configurations...

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

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

Step 2: Creating the React Frontend

  1. Set Up a Login Form in React

In your React application, create a simple login form.

// LoginForm.js
import React, { useState } from 'react';
import axios from 'axios';

const LoginForm = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [error, setError] = useState('');

    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            const { data } = await axios.post('http://localhost:5000/api/auth/login', { username, password });
            console.log('Login success:', data);
            // Save the token, handle login success (e.g., redirect, state update)
        } catch (error) {
            setError('Login failed');
            console.error(error);
        }
    };

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type="text" value={username} onChange={e => setUsername(e.target.value)} placeholder="Username" />
                <input type="password" value={password} onChange={e => setPassword(e.target.value)} placeholder="