You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.9 KiB
93 lines
2.9 KiB
using System.ComponentModel.DataAnnotations;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using API.Auth;
|
|
using API.Validation;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Model;
|
|
using Services;
|
|
|
|
namespace API.Controllers;
|
|
|
|
[ApiController]
|
|
public class AuthenticationController(IUserService service, IConfiguration config) : ControllerBase
|
|
{
|
|
private readonly SymmetricSecurityKey _key = new(Encoding.UTF8.GetBytes(config["JWT:Key"]!));
|
|
|
|
public record GenerateTokenRequest(
|
|
[MaxLength(256, ErrorMessage = "Email address is too wide")]
|
|
[EmailAddress]
|
|
string Email,
|
|
[MaxLength(256, ErrorMessage = "Password is too wide")]
|
|
string Password
|
|
);
|
|
|
|
private record AuthenticationResponse(String Token, long ExpirationDate);
|
|
|
|
[HttpPost("/auth/token")]
|
|
public async Task<IActionResult> GenerateToken([FromBody] GenerateTokenRequest req)
|
|
{
|
|
var user = await service.Authorize(req.Email, req.Password);
|
|
|
|
if (user == null)
|
|
return BadRequest(new Dictionary<string, string[]>
|
|
{
|
|
{ "unauthorized", ["Invalid email or password"] }
|
|
});
|
|
|
|
var (jwt, expirationDate) = GenerateJwt(user);
|
|
return Ok(new AuthenticationResponse(jwt, expirationDate.ToFileTimeUtc()));
|
|
}
|
|
|
|
|
|
public record RegisterAccountRequest(
|
|
[MaxLength(256, ErrorMessage = "name is longer than 256")]
|
|
string Username,
|
|
[MaxLength(256, ErrorMessage = "email is longer than 256")]
|
|
[EmailAddress]
|
|
string Email,
|
|
[StringLength(256, MinimumLength = 4, ErrorMessage = "password length must be between 4 and 256")]
|
|
string Password);
|
|
|
|
[HttpPost("/auth/register")]
|
|
public async Task<IActionResult> RegisterAccount([FromBody] RegisterAccountRequest req)
|
|
{
|
|
if (await service.GetUser(req.Email) != null)
|
|
{
|
|
return BadRequest(new Dictionary<string, string[]>
|
|
{
|
|
{ "email", ["The email address already exists"] }
|
|
});
|
|
}
|
|
|
|
|
|
var user = await service.CreateUser(
|
|
req.Username,
|
|
req.Email,
|
|
req.Password,
|
|
Constants.DefaultProfilePicture,
|
|
false
|
|
);
|
|
|
|
var (jwt, expirationDate) = GenerateJwt(user);
|
|
return Ok(new AuthenticationResponse(jwt, expirationDate.ToFileTimeUtc()));
|
|
}
|
|
|
|
|
|
private (string, DateTime) GenerateJwt(User user)
|
|
{
|
|
var claims = new List<Claim>
|
|
{
|
|
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
new(JwtRegisteredClaimNames.Sub, user.Email),
|
|
new(JwtRegisteredClaimNames.Email, user.Email),
|
|
new(IdentityData.IdUserClaimName, user.Id.ToString()),
|
|
new(IdentityData.AdminUserClaimName, user.IsAdmin.ToString())
|
|
};
|
|
|
|
return Authentication.GenerateJwt(_key, claims);
|
|
}
|
|
} |