mirror of
https://github.com/azaion/admin.git
synced 2026-04-22 11:16:33 +00:00
add postgres
This commit is contained in:
@@ -5,3 +5,4 @@ obj
|
|||||||
*.DotSettings*
|
*.DotSettings*
|
||||||
*.user
|
*.user
|
||||||
log*
|
log*
|
||||||
|
*.cmd
|
||||||
+42
-33
@@ -1,5 +1,3 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Azaion.Common;
|
using Azaion.Common;
|
||||||
using Azaion.Common.Configs;
|
using Azaion.Common.Configs;
|
||||||
@@ -9,11 +7,10 @@ using Azaion.Common.Requests;
|
|||||||
using Azaion.Services;
|
using Azaion.Services;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Configuration.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
var jwtConfig = builder.Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>();
|
var jwtConfig = builder.Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>();
|
||||||
if (jwtConfig == null)
|
if (jwtConfig == null)
|
||||||
@@ -38,12 +35,41 @@ builder.Services.AddAuthorization();
|
|||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo {Title = "Azaion.API", Version = "v1"});
|
||||||
|
c.CustomSchemaIds(type => type.ToString());
|
||||||
|
var jwtSecurityScheme = new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Scheme = "bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
Name = "JWT Authentication",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Description = "Put **_ONLY_** your JWT Bearer token on textbox below!",
|
||||||
|
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Id = JwtBearerDefaults.AuthenticationScheme,
|
||||||
|
Type = ReferenceType.SecurityScheme
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
c.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme);
|
||||||
|
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{ jwtSecurityScheme, Array.Empty<string>() }
|
||||||
|
});
|
||||||
|
});
|
||||||
builder.Services.Configure<ResourcesConfig>(builder.Configuration.GetSection(nameof(ResourcesConfig)));
|
builder.Services.Configure<ResourcesConfig>(builder.Configuration.GetSection(nameof(ResourcesConfig)));
|
||||||
|
builder.Services.Configure<JwtConfig>(builder.Configuration.GetSection(nameof(JwtConfig)));
|
||||||
|
builder.Services.Configure<ConnectionStrings>(builder.Configuration.GetSection(nameof(ConnectionStrings)));
|
||||||
|
|
||||||
builder.Services.AddScoped<IUserService, UserService>();
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
builder.Services.AddScoped<IResourcesService, ResourcesService>();
|
builder.Services.AddScoped<IResourcesService, ResourcesService>();
|
||||||
|
builder.Services.AddSingleton<IAuthService, AuthService>();
|
||||||
builder.Services.AddSingleton<IDbFactory, DbFactory>(sp => new DbFactory(sp.GetService<IOptions<ConnectionStrings>>()!.Value.AzaionDb));
|
builder.Services.AddSingleton<IDbFactory, DbFactory>();
|
||||||
|
|
||||||
builder.Services.AddValidatorsFromAssemblyContaining<RegisterUserValidator>();
|
builder.Services.AddValidatorsFromAssemblyContaining<RegisterUserValidator>();
|
||||||
|
|
||||||
@@ -61,29 +87,10 @@ app.UseAuthentication();
|
|||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapPost("/login",
|
app.MapPost("/login",
|
||||||
async (string username, string password, IUserService userService, CancellationToken cancellationToken) =>
|
async (string username, string password, IUserService userService, IAuthService authService, CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
var user = await userService.ValidateUser(username, password);
|
var user = await userService.ValidateUser(username, password, cancellationToken: cancellationToken);
|
||||||
|
return Results.Ok(new { Token = authService.CreateToken(user)});
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
|
||||||
var tokenDescriptor = new SecurityTokenDescriptor
|
|
||||||
{
|
|
||||||
Subject = new ClaimsIdentity([
|
|
||||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
|
||||||
new Claim(ClaimTypes.Name, user.Email),
|
|
||||||
new Claim(ClaimTypes.Role, user.Role.ToString()),
|
|
||||||
new Claim(Constants.HARDWARE_ID, user.HardwareId)
|
|
||||||
]),
|
|
||||||
Expires = DateTime.UtcNow.AddHours(2),
|
|
||||||
Issuer = jwtConfig.Issuer,
|
|
||||||
Audience = jwtConfig.Audience,
|
|
||||||
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature)
|
|
||||||
};
|
|
||||||
|
|
||||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
|
||||||
var tokenString = tokenHandler.WriteToken(token);
|
|
||||||
|
|
||||||
return Results.Ok(new { Token = tokenString });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapPost("/register-user",
|
app.MapPost("/register-user",
|
||||||
@@ -97,13 +104,15 @@ app.MapPost("/resources",
|
|||||||
.RequireAuthorization(p => p.RequireRole(RoleEnum.ApiAdmin.ToString()));
|
.RequireAuthorization(p => p.RequireRole(RoleEnum.ApiAdmin.ToString()));
|
||||||
|
|
||||||
app.MapPost("/resources/get",
|
app.MapPost("/resources/get",
|
||||||
async (GetResourceRequest request, IUserService userService, IResourcesService resourcesService, CancellationToken cancellationToken) =>
|
async (GetResourceRequest request, IAuthService authService, IUserService userService, IResourcesService resourcesService, CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
var user = userService.CurrentUser;
|
var user = authService.CurrentUser;
|
||||||
if (user == null)
|
if (user?.HardwareId != request.HardwareId)
|
||||||
throw new BusinessException(ExceptionEnum.NoUser, "No current user");
|
throw new BusinessException(ExceptionEnum.HardwareIdMismatch, "Hardware mismatch! You are not authorized to access this resource from this hardware.");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(user.HardwareId))
|
if (string.IsNullOrEmpty(user.HardwareId))
|
||||||
await userService.UpdateHardwareId(user.Email, request.HardwareId);
|
await userService.UpdateHardwareId(user.Email, request.HardwareId);
|
||||||
|
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
var key = Security.MakeEncryptionKey(user.Email, request.Password);
|
var key = Security.MakeEncryptionKey(user.Email, request.Password);
|
||||||
await resourcesService.GetEncryptedResource(request.ResourceEnum, key, ms, cancellationToken);
|
await resourcesService.GetEncryptedResource(request.ResourceEnum, key, ms, cancellationToken);
|
||||||
|
|||||||
@@ -4,5 +4,9 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"AzaionDb": "Host=localhost;Database=azaion;Username=azaion_reader;Password=Az@1on_re@d!only@$Az;",
|
||||||
|
"AzaionDbAdmin": "Host=localhost;Database=azaion;Username=azaion_admin;Password=Az@1on_admin$$@r;"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,10 @@
|
|||||||
"AIModelONNX": "azaion.onnx",
|
"AIModelONNX": "azaion.onnx",
|
||||||
"AIModelRKNN": "azaion.rknn"
|
"AIModelRKNN": "azaion.rknn"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"JwtConfig": {
|
||||||
|
"Issuer": "AzaionApi",
|
||||||
|
"Audience": "Annotators/OrangePi/Admins",
|
||||||
|
"TokenLifetimeHours": 2.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="11.10.0" />
|
<PackageReference Include="FluentValidation" Version="11.10.0" />
|
||||||
<PackageReference Include="linq2db" Version="5.4.1" />
|
<PackageReference Include="linq2db" Version="5.4.1" />
|
||||||
|
<PackageReference Include="Npgsql" Version="8.0.5" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Extensions.Options">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
public class ConnectionStrings
|
public class ConnectionStrings
|
||||||
{
|
{
|
||||||
public string AzaionDb { get; set; } = null!;
|
public string AzaionDb { get; set; } = null!;
|
||||||
|
public string AzaionDbAdmin { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,6 @@ public class JwtConfig
|
|||||||
{
|
{
|
||||||
public string Issuer { get; set; } = null!;
|
public string Issuer { get; set; } = null!;
|
||||||
public string Audience { get; set; } = null!;
|
public string Audience { get; set; } = null!;
|
||||||
public string Secret { get; set; }
|
public string Secret { get; set; } = null!;
|
||||||
|
public double TokenLifetimeHours { get; set; }
|
||||||
}
|
}
|
||||||
@@ -10,11 +10,19 @@ public static class AzaionDbSchemaHolder
|
|||||||
static AzaionDbSchemaHolder()
|
static AzaionDbSchemaHolder()
|
||||||
{
|
{
|
||||||
MappingSchema = new MappingSchema();
|
MappingSchema = new MappingSchema();
|
||||||
|
|
||||||
|
MappingSchema.EntityDescriptorCreatedCallback = (_, entityDescriptor) =>
|
||||||
|
{
|
||||||
|
foreach (var entityDescriptorColumn in entityDescriptor.Columns)
|
||||||
|
entityDescriptorColumn.ColumnName = entityDescriptorColumn.ColumnName.ToSnakeCase();
|
||||||
|
};
|
||||||
|
|
||||||
var builder = new FluentMappingBuilder(MappingSchema);
|
var builder = new FluentMappingBuilder(MappingSchema);
|
||||||
|
|
||||||
builder.Entity<User>()
|
builder.Entity<User>()
|
||||||
.HasTableName("users")
|
.HasTableName("users")
|
||||||
.HasIdentity(x => x.Id);
|
.HasIdentity(x => x.Id)
|
||||||
|
.Property(x => x.Role).HasConversion(v => v.ToString(), v => (RoleEnum)Enum.Parse(typeof(RoleEnum), v));
|
||||||
|
|
||||||
builder.Build();
|
builder.Build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Azaion.Common.Configs;
|
||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Azaion.Common.Database;
|
namespace Azaion.Common.Database;
|
||||||
|
|
||||||
@@ -7,27 +9,34 @@ public interface IDbFactory
|
|||||||
{
|
{
|
||||||
Task<T> Run<T>(Func<AzaionDb, Task<T>> func);
|
Task<T> Run<T>(Func<AzaionDb, Task<T>> func);
|
||||||
Task Run(Func<AzaionDb, Task> func);
|
Task Run(Func<AzaionDb, Task> func);
|
||||||
|
Task RunAdmin(Func<AzaionDb, Task> func);
|
||||||
T Run<T>(Func<AzaionDb, T> func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DbFactory : IDbFactory
|
public class DbFactory : IDbFactory
|
||||||
{
|
{
|
||||||
private readonly DataOptions _dataOptions;
|
private readonly DataOptions _dataOptions;
|
||||||
|
private readonly DataOptions _dataOptionsAdmin;
|
||||||
|
|
||||||
public DbFactory(string connectionString, bool useTracing = true, bool msSql = false)
|
public DbFactory(IOptions<ConnectionStrings> connectionString)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(connectionString))
|
_dataOptions = LoadOptions(connectionString.Value.AzaionDb);
|
||||||
throw new ArgumentException("Empty connectionString", nameof(connectionString));
|
_dataOptionsAdmin = LoadOptions(connectionString.Value.AzaionDbAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
_dataOptions = new DataOptions()
|
private DataOptions LoadOptions(string connStr)
|
||||||
.UsePostgreSQL(connectionString)
|
{
|
||||||
|
if (string.IsNullOrEmpty(connStr))
|
||||||
|
throw new ArgumentException($"Empty connection string in config!");
|
||||||
|
|
||||||
|
var dataOptions = new DataOptions()
|
||||||
|
.UsePostgreSQL(connStr)
|
||||||
.UseMappingSchema(AzaionDbSchemaHolder.MappingSchema);
|
.UseMappingSchema(AzaionDbSchemaHolder.MappingSchema);
|
||||||
|
|
||||||
if (useTracing)
|
_ = dataOptions.UseTracing(TraceLevel.Info, t => Console.WriteLine(t.SqlText));
|
||||||
_ = _dataOptions.UseTracing(TraceLevel.Info, t => Console.WriteLine(t.SqlText));
|
return dataOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<T> Run<T>(Func<AzaionDb, Task<T>> func)
|
public async Task<T> Run<T>(Func<AzaionDb, Task<T>> func)
|
||||||
{
|
{
|
||||||
await using var db = new AzaionDb(_dataOptions);
|
await using var db = new AzaionDb(_dataOptions);
|
||||||
@@ -40,9 +49,9 @@ public class DbFactory : IDbFactory
|
|||||||
await func(db);
|
await func(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Run<T>(Func<AzaionDb, T> func)
|
public async Task RunAdmin(Func<AzaionDb, Task> func)
|
||||||
{
|
{
|
||||||
using var db = new AzaionDb(_dataOptions);
|
await using var db = new AzaionDb(_dataOptionsAdmin);
|
||||||
return func(db);
|
await func(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = null!;
|
public Guid Id { get; set; }
|
||||||
public string Email { get; set; } = null!;
|
public string Email { get; set; } = null!;
|
||||||
public string PasswordHash { get; set; } = null!;
|
public string PasswordHash { get; set; } = null!;
|
||||||
public string HardwareId { get; set; } = null!;
|
public string HardwareId { get; set; } = null!;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Azaion.Common;
|
||||||
|
|
||||||
|
public static class StringExtensions
|
||||||
|
{
|
||||||
|
public static string ToSnakeCase(this string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return text;
|
||||||
|
|
||||||
|
if (text.Length < 2)
|
||||||
|
return text.ToLowerInvariant();
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(char.ToLowerInvariant(text[0]));
|
||||||
|
for (int i = 1; i < text.Length; ++i) {
|
||||||
|
var c = text[i];
|
||||||
|
if(char.IsUpper(c)) {
|
||||||
|
sb.Append('_');
|
||||||
|
sb.Append(char.ToLowerInvariant(c));
|
||||||
|
} else {
|
||||||
|
sb.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using Azaion.Common.Configs;
|
||||||
|
using Azaion.Common.Entities;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Azaion.Services;
|
||||||
|
|
||||||
|
public interface IAuthService
|
||||||
|
{
|
||||||
|
User? CurrentUser { get; }
|
||||||
|
string CreateToken(User user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthService(IHttpContextAccessor httpContextAccessor, IOptions<JwtConfig> jwtConfig) : IAuthService
|
||||||
|
{
|
||||||
|
public User? CurrentUser
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var claims = httpContextAccessor.HttpContext?.User.Claims.ToDictionary(x => x.Type);
|
||||||
|
if (claims == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!Enum.TryParse(claims[ClaimTypes.Role].Value, out RoleEnum role))
|
||||||
|
throw new ApplicationException("Invalid role");
|
||||||
|
|
||||||
|
return new User
|
||||||
|
{
|
||||||
|
Id = Guid.Parse(claims[ClaimTypes.NameIdentifier].Value),
|
||||||
|
Email = claims[ClaimTypes.Name].Value,
|
||||||
|
Role = role,
|
||||||
|
HardwareId = claims[Constants.HARDWARE_ID].Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CreateToken(User user)
|
||||||
|
{
|
||||||
|
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.Value.Secret));
|
||||||
|
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new ClaimsIdentity([
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||||
|
new Claim(ClaimTypes.Name, user.Email),
|
||||||
|
new Claim(ClaimTypes.Role, user.Role.ToString()),
|
||||||
|
new Claim(Constants.HARDWARE_ID, user.HardwareId)
|
||||||
|
]),
|
||||||
|
Expires = DateTime.UtcNow.AddHours(jwtConfig.Value.TokenLifetimeHours),
|
||||||
|
Issuer = jwtConfig.Value.Issuer,
|
||||||
|
Audience = jwtConfig.Value.Audience,
|
||||||
|
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature)
|
||||||
|
};
|
||||||
|
|
||||||
|
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
return tokenHandler.WriteToken(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,4 +19,8 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,46 +1,23 @@
|
|||||||
using System.Security.Claims;
|
using Azaion.Common;
|
||||||
using Azaion.Common;
|
|
||||||
using Azaion.Common.Configs;
|
|
||||||
using Azaion.Common.Database;
|
using Azaion.Common.Database;
|
||||||
using Azaion.Common.Entities;
|
using Azaion.Common.Entities;
|
||||||
using Azaion.Common.Requests;
|
using Azaion.Common.Requests;
|
||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace Azaion.Services;
|
namespace Azaion.Services;
|
||||||
|
|
||||||
public interface IUserService
|
public interface IUserService
|
||||||
{
|
{
|
||||||
User? CurrentUser { get; }
|
|
||||||
Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default);
|
Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default);
|
||||||
Task<User> ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default);
|
Task<User> ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default);
|
||||||
Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default);
|
Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserService(IDbFactory dbFactory, IHttpContextAccessor httpContextAccessor) : IUserService
|
public class UserService(IDbFactory dbFactory) : IUserService
|
||||||
{
|
{
|
||||||
public User? CurrentUser
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var claims = httpContextAccessor.HttpContext?.User.Claims.ToDictionary(x => x.Type);
|
|
||||||
if (claims == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Enum.TryParse(claims[ClaimTypes.Role].Value, out RoleEnum role);
|
|
||||||
return new User
|
|
||||||
{
|
|
||||||
Id = claims[ClaimTypes.NameIdentifier].Value,
|
|
||||||
Email = claims[ClaimTypes.Name].Value,
|
|
||||||
Role = role,
|
|
||||||
HardwareId = claims[Constants.HARDWARE_ID].Value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default)
|
public async Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await dbFactory.Run(async db =>
|
await dbFactory.RunAdmin(async db =>
|
||||||
{
|
{
|
||||||
var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Email == request.Email, token: cancellationToken);
|
var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Email == request.Email, token: cancellationToken);
|
||||||
if (existingUser != null)
|
if (existingUser != null)
|
||||||
@@ -75,6 +52,6 @@ public class UserService(IDbFactory dbFactory, IHttpContextAccessor httpContextA
|
|||||||
});
|
});
|
||||||
|
|
||||||
public async Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default) =>
|
public async Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default) =>
|
||||||
await dbFactory.Run(async db =>
|
await dbFactory.RunAdmin(async db =>
|
||||||
await db.Users.UpdateAsync(x => x.Email == username, u => new User { HardwareId = hardwareId}, token: cancellationToken));
|
await db.Users.UpdateAsync(x => x.Email == username, u => new User { HardwareId = hardwareId}, token: cancellationToken));
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+29
@@ -0,0 +1,29 @@
|
|||||||
|
create database azaion;
|
||||||
|
-- make sure you connect to azaion db
|
||||||
|
|
||||||
|
--superadmin user
|
||||||
|
create role azaion_superadmin with login password 'superadmin_pass';
|
||||||
|
grant all privileges on all tables in schema public to azaion_superadmin;
|
||||||
|
|
||||||
|
--writer user
|
||||||
|
create role azaion_admin with login password 'admin_pass';
|
||||||
|
grant connect on database azaion to azaion_admin;
|
||||||
|
grant usage on schema public to azaion_admin;
|
||||||
|
|
||||||
|
--readonly user
|
||||||
|
create role azaion_reader with login password 'reader_pass';
|
||||||
|
grant connect on database azaion to azaion_reader;
|
||||||
|
grant usage on schema public to azaion_reader;
|
||||||
|
|
||||||
|
|
||||||
|
-- users table
|
||||||
|
create table users
|
||||||
|
(
|
||||||
|
id uuid primary key,
|
||||||
|
email varchar(160) not null,
|
||||||
|
password_hash varchar(255) not null,
|
||||||
|
hardware_id varchar(120) not null,
|
||||||
|
role varchar(20) not null
|
||||||
|
);
|
||||||
|
grant select, insert, update, delete on public.users to azaion_admin;
|
||||||
|
grant select on table public.users to azaion_reader;
|
||||||
Reference in New Issue
Block a user