Add login function in backend

This commit is contained in:
ReiMerc 2023-12-08 01:05:55 +01:00
parent 91b6127152
commit 5141ebf0f1
6 changed files with 161 additions and 21 deletions

View File

@ -6,6 +6,6 @@ namespace backend.Application
public static class ApplicationState public static class ApplicationState
{ {
public static IMqttClient? MqttClient { get; set; } public static IMqttClient? MqttClient { get; set; }
public static DbContext? DbContext { get; set; } public static DispenserContext? DbContext { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@ using backend.Application;
using backend.Models; using backend.Models;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using System.Web;
namespace backend.Controllers; namespace backend.Controllers;
@ -12,24 +13,29 @@ public class UserController : ControllerBase
[HttpPost("Register")] [HttpPost("Register")]
public IActionResult Register([FromBody] JsonObject input) public IActionResult Register([FromBody] JsonObject input)
{ {
if (input["username"] == null || input["password"] == null) { // Validate
if (String.IsNullOrEmpty(input["username"]?.ToString()) || String.IsNullOrEmpty(input["password"]?.ToString())) {
return BadRequest("Username and password required"); return BadRequest("Username and password required");
} }
// Hash password
var passwordHasher = new PasswordHasher<object>(); var passwordHasher = new PasswordHasher<object>();
string hashedPassword = passwordHasher.HashPassword(null, input["password"]!.ToString()); string hashedPassword = passwordHasher.HashPassword(null, input["password"]!.ToString());
// Generate touch code
string touchCode = ""; string touchCode = "";
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
touchCode += (1 + new Random().Next() % 5).ToString(); touchCode += (1 + new Random().Next() % 5).ToString();
} }
// Create user
var user = new User { var user = new User {
Username = input["username"]!.ToString(), Username = input["username"]!.ToString(),
Password = hashedPassword, Password = hashedPassword,
TouchCode = touchCode, TouchCode = touchCode,
}; };
// Save user
ApplicationState.DbContext!.Add(user); ApplicationState.DbContext!.Add(user);
ApplicationState.DbContext!.SaveChanges(); ApplicationState.DbContext!.SaveChanges();
@ -37,4 +43,42 @@ public class UserController : ControllerBase
return Ok(); return Ok();
} }
[HttpPost("Login")]
public IActionResult Login([FromBody] JsonObject input)
{
// Validate
if (String.IsNullOrEmpty(input["username"]?.ToString()) || String.IsNullOrEmpty(input["password"]?.ToString())) {
return BadRequest("Username and password required");
}
if (Request.Cookies["session"] != null) {
return BadRequest("You are already logged in");
}
// Get user
var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.Username == input["username"]!.ToString());
if (user == null) {
return BadRequest("Invalid username");
}
// Verify password
var passwordHasher = new PasswordHasher<object>();
if (passwordHasher.VerifyHashedPassword(null, user.Password, input["password"]!.ToString()) == PasswordVerificationResult.Failed) {
return BadRequest("Invalid password");
}
// Create session token if necessary
if (string.IsNullOrEmpty(user.SessionToken)) {
user.SessionToken = Guid.NewGuid().ToString();
ApplicationState.DbContext!.SaveChanges();
}
// Set session cookie
Response.Cookies.Append("session", user.SessionToken);
Console.WriteLine(user.Username + " has logged in");
return Ok();
}
} }

View File

@ -0,0 +1,64 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace backend.Migrations
{
[DbContext(typeof(DispenserContext))]
[Migration("20231207234050_AddSessionTokenToUser")]
partial class AddSessionTokenToUser
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0");
modelBuilder.Entity("backend.Models.DispenserLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("Timestamp")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("DispenserLogs");
});
modelBuilder.Entity("backend.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SessionToken")
.HasColumnType("TEXT");
b.Property<string>("TouchCode")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Users");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace backend.Migrations
{
/// <inheritdoc />
public partial class AddSessionTokenToUser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "SessionToken",
table: "Users",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SessionToken",
table: "Users");
}
}
}

View File

@ -40,6 +40,9 @@ namespace backend.Migrations
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("SessionToken")
.HasColumnType("TEXT");
b.Property<string>("TouchCode") b.Property<string>("TouchCode")
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View File

@ -12,4 +12,5 @@ public class User
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string TouchCode { get; set; } public string TouchCode { get; set; }
public string? SessionToken { get; set; }
} }