mirror of
https://github.com/azaion/admin.git
synced 2026-04-22 08:46:34 +00:00
b1693b2894
use <FrameworkReference Include="Microsoft.AspNetCore.App" /> instead of old nuget packages
189 lines
7.5 KiB
C#
189 lines
7.5 KiB
C#
using System.Text;
|
|
using Azaion.Common;
|
|
using Azaion.Common.Configs;
|
|
using Azaion.Common.Database;
|
|
using Azaion.Common.Entities;
|
|
using Azaion.Common.Requests;
|
|
using Azaion.Services;
|
|
using FluentValidation;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Rewrite;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Microsoft.OpenApi.Models;
|
|
using Serilog;
|
|
|
|
Log.Logger = new LoggerConfiguration()
|
|
.Enrich.FromLogContext()
|
|
.MinimumLevel.Information()
|
|
.WriteTo.Console()
|
|
.WriteTo.File(
|
|
path: "logs/log.txt",
|
|
rollingInterval: RollingInterval.Day)
|
|
.CreateLogger();
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
builder.WebHost.ConfigureKestrel(o => o.Limits.MaxRequestBodySize = 209715200); //increase upload limit up to 200mb
|
|
|
|
var jwtConfig = builder.Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>();
|
|
if (jwtConfig == null || string.IsNullOrEmpty(jwtConfig.Secret))
|
|
throw new Exception("Missing configuration section: JwtConfig");
|
|
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.Secret));
|
|
|
|
builder.Services.AddSerilog();
|
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
.AddJwtBearer(o =>
|
|
{
|
|
o.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuer = true,
|
|
ValidateAudience = true,
|
|
ValidateLifetime = true,
|
|
ValidateIssuerSigningKey = true,
|
|
ValidIssuer = jwtConfig.Issuer,
|
|
ValidAudience = jwtConfig.Audience,
|
|
IssuerSigningKey = signingKey
|
|
};
|
|
});
|
|
|
|
#region Policies
|
|
|
|
var apiAdminPolicy = new AuthorizationPolicyBuilder()
|
|
.RequireRole(RoleEnum.ApiAdmin.ToString()).Build();
|
|
|
|
var apiUploaderPolicy = new AuthorizationPolicyBuilder()
|
|
.RequireRole(RoleEnum.ResourceUploader.ToString(), RoleEnum.ApiAdmin.ToString()).Build();
|
|
|
|
builder.Services.AddAuthorization(o =>
|
|
{
|
|
o.AddPolicy(nameof(apiAdminPolicy), apiAdminPolicy);
|
|
o.AddPolicy(nameof(apiUploaderPolicy), apiUploaderPolicy);
|
|
});
|
|
|
|
#endregion Policies
|
|
|
|
|
|
builder.Services.AddHttpContextAccessor();
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
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<JwtConfig>(builder.Configuration.GetSection(nameof(JwtConfig)));
|
|
builder.Services.Configure<ConnectionStrings>(builder.Configuration.GetSection(nameof(ConnectionStrings)));
|
|
|
|
builder.Services.AddScoped<IUserService, UserService>();
|
|
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
builder.Services.AddScoped<IResourcesService, ResourcesService>();
|
|
builder.Services.AddSingleton<IDbFactory, DbFactory>();
|
|
|
|
builder.Services.AddLazyCache();
|
|
builder.Services.AddScoped<ICache, MemoryCache>();
|
|
|
|
builder.Services.AddValidatorsFromAssemblyContaining<RegisterUserValidator>();
|
|
|
|
builder.Services.AddExceptionHandler<BusinessExceptionHandler>();
|
|
var app = builder.Build();
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
}
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
app.UseRewriter(new RewriteOptions().AddRedirect("^$", "/swagger"));
|
|
|
|
app.MapPost("/login",
|
|
async (LoginRequest request, IUserService userService, IAuthService authService, CancellationToken cancellationToken) =>
|
|
{
|
|
var user = await userService.ValidateUser(request, cancellationToken: cancellationToken);
|
|
return Results.Ok(new { Token = authService.CreateToken(user)});
|
|
})
|
|
.WithOpenApi(op => new(op){ Summary = "Login"});;
|
|
|
|
app.MapPost("/users",
|
|
async (RegisterUserRequest registerUserRequest, IUserService userService, CancellationToken cancellationToken)
|
|
=> await userService.RegisterUser(registerUserRequest, cancellationToken))
|
|
.RequireAuthorization(apiAdminPolicy)
|
|
.WithOpenApi(op => new(op){ Summary = "Creates a new user"});
|
|
|
|
app.MapGet("/currentuser",
|
|
async (IAuthService authService) => await authService.GetCurrentUser())
|
|
.RequireAuthorization()
|
|
.WithOpenApi(op => new(op){ Summary = "Get Current User"});
|
|
|
|
app.MapGet("/users",
|
|
async (string? searchEmail, RoleEnum? searchRole, IUserService userService, CancellationToken cancellationToken)
|
|
=> await userService.GetUsers(searchEmail, searchRole, cancellationToken))
|
|
.RequireAuthorization(apiAdminPolicy)
|
|
.WithOpenApi(op => new(op){ Summary = "List users by criteria"});
|
|
|
|
app.MapPost("/resources/{dataFolder?}",
|
|
async ([FromRoute]string? dataFolder, IFormFile data, IResourcesService resourceService, CancellationToken cancellationToken)
|
|
=> await resourceService.SaveResource(dataFolder, data, cancellationToken))
|
|
.Accepts<IFormFile>("multipart/form-data")
|
|
.RequireAuthorization()
|
|
//.WithOpenApi(op => new(op){ Summary = "Upload resource"}); //For some reason doesn't work when this is specified.
|
|
.DisableAntiforgery();
|
|
|
|
app.MapPost("/resources/get/{dataFolder?}", //Need to have POST method for secure password
|
|
async ([FromBody]GetResourceRequest request, [FromRoute]string? dataFolder, IAuthService authService, IUserService userService, IResourcesService resourcesService, CancellationToken cancellationToken) =>
|
|
{
|
|
var user = await authService.GetCurrentUser();
|
|
if (user == null)
|
|
throw new UnauthorizedAccessException();
|
|
|
|
var hwHash = await userService.CheckHardwareHash(user, request);
|
|
|
|
var key = Security.GetApiEncryptionKey(user.Email, request.Password, hwHash);
|
|
var stream = await resourcesService.GetEncryptedResource(dataFolder, request.FileName, key, cancellationToken);
|
|
|
|
return Results.File(stream, "application/octet-stream", request.FileName);
|
|
}).RequireAuthorization()
|
|
.WithOpenApi(op => new OpenApiOperation(op){ Summary = "Gets encrypted by users Password and HardwareHash resources. POST method for secure password"});
|
|
|
|
app.MapPut("/resources/reset-hardware",
|
|
async (string email, IUserService userService, ICache cache, CancellationToken cancellationToken) =>
|
|
await userService.UpdateHardware(email, new HardwareInfo(), cancellationToken))
|
|
.RequireAuthorization(apiAdminPolicy)
|
|
.WithOpenApi(op => new OpenApiOperation(op){ Summary = "Resets hardware id in case of hardware change"});
|
|
|
|
app.MapPut("/users/queue-offsets/{email}",
|
|
async ([FromRoute] string email, UserQueueOffsets offsets, IUserService userService, CancellationToken cancellationToken)
|
|
=> await userService.UpdateQueueOffsets(email, offsets, cancellationToken))
|
|
.RequireAuthorization()
|
|
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Updates user queue offsets" });
|
|
|
|
app.UseExceptionHandler(_ => {});
|
|
|
|
app.Run();
|