mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Added new API for getting Member (aka Users but for use in FE). User is just used for login/registering.
This commit is contained in:
parent
a920be092d
commit
13ed323949
@ -5,6 +5,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" NoWarn="NU1605" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" NoWarn="NU1605" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.1" NoWarn="NU1605" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.1" NoWarn="NU1605" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1">
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Cryptography;
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
@ -15,12 +16,14 @@ namespace API.Controllers
|
|||||||
{
|
{
|
||||||
private readonly DataContext _context;
|
private readonly DataContext _context;
|
||||||
private readonly ITokenService _tokenService;
|
private readonly ITokenService _tokenService;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
private readonly ILogger<AccountController> _logger;
|
private readonly ILogger<AccountController> _logger;
|
||||||
|
|
||||||
public AccountController(DataContext context, ITokenService tokenService, ILogger<AccountController> logger)
|
public AccountController(DataContext context, ITokenService tokenService, IUserRepository userRepository, ILogger<AccountController> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_tokenService = tokenService;
|
_tokenService = tokenService;
|
||||||
|
_userRepository = userRepository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +42,8 @@ namespace API.Controllers
|
|||||||
UserName = registerDto.Username.ToLower(),
|
UserName = registerDto.Username.ToLower(),
|
||||||
PasswordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(registerDto.Password)),
|
PasswordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(registerDto.Password)),
|
||||||
PasswordSalt = hmac.Key,
|
PasswordSalt = hmac.Key,
|
||||||
IsAdmin = registerDto.IsAdmin
|
IsAdmin = registerDto.IsAdmin,
|
||||||
|
LastActive = DateTime.Now
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.Users.Add(user);
|
_context.Users.Add(user);
|
||||||
@ -69,10 +73,16 @@ namespace API.Controllers
|
|||||||
if (computedHash[i] != user.PasswordHash[i]) return Unauthorized("Invalid password");
|
if (computedHash[i] != user.PasswordHash[i]) return Unauthorized("Invalid password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update LastActive on account
|
||||||
|
user.LastActive = DateTime.Now;
|
||||||
|
_userRepository.Update(user);
|
||||||
|
await _userRepository.SaveAllAsync();
|
||||||
|
|
||||||
return new UserDto()
|
return new UserDto()
|
||||||
{
|
{
|
||||||
Username = user.UserName,
|
Username = user.UserName,
|
||||||
Token = _tokenService.CreateToken(user)
|
Token = _tokenService.CreateToken(user),
|
||||||
|
IsAdmin = user.IsAdmin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
API/Controllers/UsersController.cs
Normal file
28
API/Controllers/UsersController.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using API.Data;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace API.Controllers
|
||||||
|
{
|
||||||
|
public class UsersController : BaseApiController
|
||||||
|
{
|
||||||
|
private readonly DataContext _context;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public UsersController(DataContext context, IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<MemberDto>>> GetUsers()
|
||||||
|
{
|
||||||
|
return Ok(await _userRepository.GetMembersAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace API.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a number to a boolean.
|
|
||||||
/// This is needed for HDHomerun.
|
|
||||||
/// </summary>
|
|
||||||
public class JsonBoolNumberConverter : JsonConverter<bool>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.Number)
|
|
||||||
{
|
|
||||||
return Convert.ToBoolean(reader.GetInt32());
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.GetBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteBooleanValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace API.Converters
|
|
||||||
{
|
|
||||||
public class JsonBoolStringConverter : JsonConverter<bool>
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.String)
|
|
||||||
{
|
|
||||||
return reader.GetString().ToLower() == "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.GetBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteBooleanValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
16
API/DTOs/MemberDto.cs
Normal file
16
API/DTOs/MemberDto.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace API.DTOs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a member of a Kavita server.
|
||||||
|
/// </summary>
|
||||||
|
public class MemberDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public DateTime Created { get; set; }
|
||||||
|
public DateTime LastActive { get; set; }
|
||||||
|
public bool IsAdmin { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using API.Converters;
|
|
||||||
|
|
||||||
namespace API.DTOs
|
namespace API.DTOs
|
||||||
{
|
{
|
||||||
@ -11,7 +9,6 @@ namespace API.DTOs
|
|||||||
[Required]
|
[Required]
|
||||||
[StringLength(8, MinimumLength = 4)]
|
[StringLength(8, MinimumLength = 4)]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
[JsonConverter(typeof(JsonBoolNumberConverter))]
|
|
||||||
public bool IsAdmin { get; set; }
|
public bool IsAdmin { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
61
API/Data/UserRepository.cs
Normal file
61
API/Data/UserRepository.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Entities;
|
||||||
|
using API.Interfaces;
|
||||||
|
using AutoMapper;
|
||||||
|
using AutoMapper.QueryableExtensions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace API.Data
|
||||||
|
{
|
||||||
|
public class UserRepository : IUserRepository
|
||||||
|
{
|
||||||
|
private readonly DataContext _context;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public UserRepository(DataContext context, IMapper mapper)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(AppUser user)
|
||||||
|
{
|
||||||
|
_context.Entry(user).State = EntityState.Modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SaveAllAsync()
|
||||||
|
{
|
||||||
|
return await _context.SaveChangesAsync() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<AppUser>> GetUsersAsync()
|
||||||
|
{
|
||||||
|
return await _context.Users.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AppUser> GetUserByIdAsync(int id)
|
||||||
|
{
|
||||||
|
return await _context.Users.FindAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AppUser> GetUserByUsernameAsync(string username)
|
||||||
|
{
|
||||||
|
return await _context.Users.SingleOrDefaultAsync(x => x.UserName == username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<MemberDto>> GetMembersAsync()
|
||||||
|
{
|
||||||
|
return await _context.Users.ProjectTo<MemberDto>(_mapper.ConfigurationProvider).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MemberDto> GetMemberAsync(string username)
|
||||||
|
{
|
||||||
|
return await _context.Users.Where(x => x.UserName == username)
|
||||||
|
.ProjectTo<MemberDto>(_mapper.ConfigurationProvider)
|
||||||
|
.SingleOrDefaultAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using API.Data;
|
using API.Data;
|
||||||
|
using API.Helpers;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
using API.Services;
|
using API.Services;
|
||||||
|
using AutoMapper;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -11,6 +13,8 @@ namespace API.Extensions
|
|||||||
{
|
{
|
||||||
public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration config)
|
public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration config)
|
||||||
{
|
{
|
||||||
|
services.AddAutoMapper(typeof(AutoMapperProfiles).Assembly);
|
||||||
|
services.AddScoped<IUserRepository, UserRepository>();
|
||||||
services.AddScoped<ITokenService, TokenService>();
|
services.AddScoped<ITokenService, TokenService>();
|
||||||
services.AddDbContext<DataContext>(options =>
|
services.AddDbContext<DataContext>(options =>
|
||||||
{
|
{
|
||||||
|
12
API/Extensions/ClaimsPrincipalExtensions.cs
Normal file
12
API/Extensions/ClaimsPrincipalExtensions.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace API.Extensions
|
||||||
|
{
|
||||||
|
public static class ClaimsPrincipalExtensions
|
||||||
|
{
|
||||||
|
public static string GetUsername(this ClaimsPrincipal user)
|
||||||
|
{
|
||||||
|
return user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
API/Helpers/AutoMapperProfiles.cs
Normal file
14
API/Helpers/AutoMapperProfiles.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using API.DTOs;
|
||||||
|
using API.Entities;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace API.Helpers
|
||||||
|
{
|
||||||
|
public class AutoMapperProfiles : Profile
|
||||||
|
{
|
||||||
|
public AutoMapperProfiles()
|
||||||
|
{
|
||||||
|
CreateMap<AppUser, MemberDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
API/Interfaces/IUserRepository.cs
Normal file
19
API/Interfaces/IUserRepository.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Entities;
|
||||||
|
|
||||||
|
namespace API.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUserRepository
|
||||||
|
{
|
||||||
|
void Update(AppUser user);
|
||||||
|
Task<bool> SaveAllAsync();
|
||||||
|
Task<IEnumerable<AppUser>> GetUsersAsync();
|
||||||
|
Task<AppUser> GetUserByIdAsync(int id);
|
||||||
|
Task<AppUser> GetUserByUsernameAsync(string username);
|
||||||
|
Task<IEnumerable<MemberDto>> GetMembersAsync();
|
||||||
|
Task<MemberDto> GetMemberAsync(string username);
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ namespace API.Middleware
|
|||||||
private readonly ILogger<ExceptionMiddleware> _logger;
|
private readonly ILogger<ExceptionMiddleware> _logger;
|
||||||
private readonly IHostEnvironment _env;
|
private readonly IHostEnvironment _env;
|
||||||
|
|
||||||
|
|
||||||
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger, IHostEnvironment env)
|
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger, IHostEnvironment env)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
"launchBrowser": false,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"API": {
|
"API": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": "true",
|
"dotnetRunMessages": "true",
|
||||||
"launchBrowser": true,
|
"launchBrowser": false,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user