Working on auth implentation.

This commit is contained in:
Max 2023-09-17 21:41:31 +02:00
parent 952e0d7e3e
commit 8511401bff
9 changed files with 131 additions and 26 deletions

View File

@ -0,0 +1,15 @@
using System;
namespace SharpRSS.API.Contracts
{
public class ApiError
{
public ApiError()
{
}
public bool Logged { get; set; }
public string Message { get; set; } = string.Empty;
public DateTime Date { get; set; }
}
}

View File

@ -0,0 +1,16 @@
namespace SharpRSS.API.Contracts.DTO
{
public class ApiListResult<TResultValue>
{
public ApiListResult(int hits, int total, TResultValue? data)
{
Hits = hits;
Total = total;
Data = data;
}
public int Hits { get; }
public int Total { get; }
public TResultValue? Data { get; }
}
}

View File

@ -0,0 +1,8 @@
namespace SharpRSS.API.Contracts.Models.User
{
public class AuthenticateUser
{
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using ToolQit;
using ToolQit.Logging;
namespace SharpRSS.API.Auth
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class SessionAuthorizeAttribute : Attribute, IAuthorizationFilter
{
public SessionAuthorizeAttribute(string permission = "")
{
_log = LogManager.CreateLogger(typeof(SessionAuthorizeAttribute));
_perm = permission;
}
private readonly ILog _log;
private readonly string _perm;
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.ActionDescriptor.EndpointMetadata.Any(obj => obj.GetType() == typeof(AllowAnonymousAttribute)))
{
context.Result = new OkResult();
return;
}
//TODO: Check session ID!
context.Result = new UnauthorizedResult();
}
}
}

View File

@ -1,7 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SharpRSS.API.Auth;
using SharpRSS.API.Contracts;
using SharpRSS.API.Contracts.DTO;
using SharpRSS.API.Contracts.Models.User;
using SharpRSS.API.Data;
using SharpRSS.API.Models;
using SharpRSS.API.Models.Auth;
@ -9,6 +14,7 @@ using SharpRSS.API.Models.Auth;
namespace SharpRSS.API.Controllers
{
[ApiController]
[SessionAuthorize]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
@ -19,13 +25,28 @@ namespace SharpRSS.API.Controllers
private readonly AuthService _authService;
[HttpPost("create")]
public async Task<ActionResult<UserDto>> CreateUser(UserRequest user)
[HttpPost("[action]")]
[AllowAnonymous]
public async Task<ActionResult<string>> Authenticate(AuthenticateUser authenticateUser)
{
Result<User> result = await _authService.CreateUser(user);
return Ok("Ok!");
}
[HttpPost("user")]
public async Task<ActionResult<UserDto>> CreateUser(AuthenticateUser authenticateUser)
{
Result<User> result = await _authService.CreateUser(authenticateUser);
if (result.Success)
return Ok(Models.Auth.User.ToDto(result.Value ?? new User()));
return BadRequest(new ApiResult(result.Message, ApiResults.Error));
}
[HttpGet("user")]
public async Task<ActionResult<ApiListResult<IEnumerable<UserDto>>>> GetUsers(int take, int skip)
{
var usersAuth = await _authService.GetUsers(take, skip);
List<UserDto> users = usersAuth.Value?.Select(Models.Auth.User.ToDto).ToList() ?? new List<UserDto>();
return Ok(new ApiListResult<IEnumerable<UserDto>>(users.Count, await _authService.UserCount(), users));
}
}
}

View File

@ -1,4 +1,3 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
@ -9,7 +8,7 @@ namespace SharpRSS.API.Cryptography
{
private const int KeySize = 128;
private const int Iterations = 420069;
static readonly HashAlgorithmName Algorithm = HashAlgorithmName.SHA512;
private static readonly HashAlgorithmName Algorithm = HashAlgorithmName.SHA512;
public static byte[] HashPassword(string password, out byte[] salt)
{

View File

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using SharpRSS.API.Contracts.Models.User;
using SharpRSS.API.Cryptography;
using SharpRSS.API.Models;
using SharpRSS.API.Models.Auth;
@ -23,19 +24,22 @@ namespace SharpRSS.API.Data
private readonly IConfiguration _configuration;
private readonly ILog _log;
public async Task<Result<User>> CreateUser(UserRequest userRequest)
public async Task<Result<User>> CreateUser(AuthenticateUser authenticateUserRequest)
{
bool result = false;
await using DbAccess access = new DbAccess(_configuration);
bool result;
if (authenticateUserRequest.UserName.Any(char.IsWhiteSpace))
return new Result<User>(null, message: "Username should not contain space/whitespaces!");
var user = access.Users.FirstOrDefault(u => u.UserName == userRequest.UserName);
await using DbAccess access = new DbAccess(_configuration);
var user = access.Users.FirstOrDefault(u => u.UserName == authenticateUserRequest.UserName);
if (user != null)
return new Result<User>(user, message:"User name already exists!");
byte[] hashedPwdBytes = Hasher.HashPassword(userRequest.Password, out byte[] salt);
byte[] hashedPwdBytes = Hasher.HashPassword(authenticateUserRequest.Password, out byte[] salt);
user = new User()
{
UserName = userRequest.UserName,
Mail = userRequest.EMail,
UserName = authenticateUserRequest.UserName,
Mail = "",
Password = hashedPwdBytes,
Salt = salt
};
@ -50,7 +54,24 @@ namespace SharpRSS.API.Data
_log.Error(e, "Error creating user: {UserName}", user.UserName);
return new Result<User>(user, message: "Could not create user!");
}
return new Result<User>(user, result);
return new Result<User>(user, result, "Ok");
}
public async Task<Result<IEnumerable<User>>> GetUsers(int take = 50, int skip = 0)
{
if (take is 0 or > 50)
take = 50;
await using DbAccess access = new DbAccess(_configuration);
IEnumerable<User> users = access.Users.Skip(skip).Take(take).ToList();
if (!users.Any())
return new Result<IEnumerable<User>>(users, false, "No users found!");
return new Result<IEnumerable<User>>(users, true, "Ok");
}
public async Task<int> UserCount()
{
await using DbAccess access = new DbAccess(_configuration);
return access.Users.Count();
}
}
}

View File

@ -1,9 +0,0 @@
namespace SharpRSS.API.Models.Auth
{
public class UserRequest
{
public string UserName { get; set; }
public string EMail { get; set; }
public string Password { get; set; }
}
}

View File

@ -2,7 +2,7 @@ namespace SharpRSS.API.Models
{
public class Result<TValue>
{
public Result(TValue value, bool success = false, string message = "")
public Result(TValue? value, bool success = false, string message = "")
{
Value = value;
Success = success;