Compare commits
1 Commits
2b1357e981
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dd0c6e6f73 |
6
backend-dotnet/.dockerignore
Normal file
6
backend-dotnet/.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
.vs/
|
||||||
|
|
||||||
12
backend-dotnet/.gitignore
vendored
Normal file
12
backend-dotnet/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
## .NET
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
27
backend-dotnet/AppConfig.cs
Normal file
27
backend-dotnet/AppConfig.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace DexDemoBackend;
|
||||||
|
|
||||||
|
public class AppConfig
|
||||||
|
{
|
||||||
|
public string DbHost { get; set; } = "postgres";
|
||||||
|
public string DbPort { get; set; } = "5440";
|
||||||
|
public string DbName { get; set; } = "dexdemo";
|
||||||
|
public string DbUser { get; set; } = "dexdemo";
|
||||||
|
public string DbPassword { get; set; } = "dexdemo";
|
||||||
|
public string Issuer { get; set; } = "https://dex.127.0.0.1.sslip.io/";
|
||||||
|
public bool InsecureDevMode { get; set; }
|
||||||
|
public string? InsecureDevEmail { get; set; }
|
||||||
|
public string[] AllowedOrigins { get; set; } = ["http://localhost:3000", "https://localhost:3000"];
|
||||||
|
|
||||||
|
// JWT configuration
|
||||||
|
public string NameClaimType { get; set; } = "name";
|
||||||
|
public string RoleClaimType { get; set; } = "role";
|
||||||
|
public string EmailClaimType { get; set; } = "email";
|
||||||
|
public string AuthRequestEmailHeader { get; set; } = "X-Auth-Request-Email";
|
||||||
|
public TimeSpan ClockSkew { get; set; } = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
public string ConnectionString =>
|
||||||
|
$"Host={DbHost};Port={DbPort};Database={DbName};Username={DbUser};Password={DbPassword}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
18
backend-dotnet/Dockerfile
Normal file
18
backend-dotnet/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY *.csproj .
|
||||||
|
RUN dotnet restore
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN dotnet publish -c Release -o /app/publish
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
ENV ASPNETCORE_URLS=http://+:8000
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet", "backend-dotnet.dll"]
|
||||||
|
|
||||||
36
backend-dotnet/InsecureDevAuthenticationHandler.cs
Normal file
36
backend-dotnet/InsecureDevAuthenticationHandler.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using DexDemoBackend;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
|
public class InsecureDevAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||||
|
{
|
||||||
|
private readonly AppConfig _config;
|
||||||
|
|
||||||
|
public InsecureDevAuthenticationHandler(
|
||||||
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
AppConfig config) : base(options, logger, encoder)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
var email = _config.InsecureDevEmail ?? "dev@example.com";
|
||||||
|
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, email),
|
||||||
|
new Claim(_config.EmailClaimType, email)
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(claims, Scheme.Name);
|
||||||
|
var principal = new ClaimsPrincipal(identity);
|
||||||
|
var ticket = new AuthenticationTicket(principal, Scheme.Name);
|
||||||
|
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||||
|
}
|
||||||
|
}
|
||||||
16
backend-dotnet/Models.cs
Normal file
16
backend-dotnet/Models.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace DexDemoBackend;
|
||||||
|
|
||||||
|
public record Organization(int Id, string Name);
|
||||||
|
|
||||||
|
public record Role(int Id, string Name, string? Description);
|
||||||
|
|
||||||
|
public record Link(int Id, string Title, string Url, string? Description);
|
||||||
|
|
||||||
|
public record UserInfo(
|
||||||
|
string Email,
|
||||||
|
string FullName,
|
||||||
|
Organization? Organization,
|
||||||
|
List<Role> Roles,
|
||||||
|
List<Link> AvailableLinks
|
||||||
|
);
|
||||||
|
|
||||||
276
backend-dotnet/Program.cs
Normal file
276
backend-dotnet/Program.cs
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
using Dapper;
|
||||||
|
using DexDemoBackend;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
using Microsoft.IdentityModel.Protocols;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Npgsql;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.Configure<AppConfig>(builder.Configuration.GetSection("AppConfig"));
|
||||||
|
builder.Services.AddSingleton(sp => sp.GetRequiredService<Microsoft.Extensions.Options.IOptions<AppConfig>>().Value);
|
||||||
|
|
||||||
|
var config = builder.Configuration.GetSection("AppConfig").Get<AppConfig>() ?? new AppConfig();
|
||||||
|
|
||||||
|
ValidateConfiguration(config);
|
||||||
|
|
||||||
|
ConfigureJwtAuthentication(builder.Services, config);
|
||||||
|
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddDefaultPolicy(policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins(config.AllowedOrigins)
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
|
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||||
|
{
|
||||||
|
options.SerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.SnakeCaseLower;
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
|
||||||
|
|
||||||
|
app.UseCors();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||||
|
await context.Response.WriteAsJsonAsync(new { error = "Unauthorized" });
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
await context.Response.WriteAsJsonAsync(new { error = "Internal server error" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/health", () => Results.Ok(new HealthResponse("ok")));
|
||||||
|
|
||||||
|
app.MapGet("/api/user-identity", [Authorize] (HttpContext context) =>
|
||||||
|
{
|
||||||
|
return Results.Ok(new UserIdentityResponse(
|
||||||
|
context.User.Identity?.Name,
|
||||||
|
context.User.Identity?.IsAuthenticated ?? false,
|
||||||
|
context.User.Identity?.AuthenticationType,
|
||||||
|
context.User.Claims.Select(c => new ClaimResponse(c.Type, c.Value)).ToList()
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/user-info", [Authorize] async (HttpContext context, [FromServices] AppConfig cfg) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var email = await GetUserEmail(context, cfg);
|
||||||
|
|
||||||
|
await using var conn = new NpgsqlConnection(cfg.ConnectionString);
|
||||||
|
await conn.OpenAsync();
|
||||||
|
|
||||||
|
var userData = await conn.QueryAsync<UserDataResult>(@"
|
||||||
|
SELECT
|
||||||
|
u.email, u.full_name,
|
||||||
|
o.id as org_id, o.name as org_name,
|
||||||
|
r.id as role_id, r.name as role_name, r.description as role_description,
|
||||||
|
l.id as link_id, l.title as link_title, l.url as link_url, l.description as link_description
|
||||||
|
FROM users u
|
||||||
|
LEFT JOIN organizations o ON u.organization_id = o.id
|
||||||
|
LEFT JOIN user_roles ur ON u.id = ur.user_id
|
||||||
|
LEFT JOIN roles r ON ur.role_id = r.id
|
||||||
|
LEFT JOIN role_links rl ON r.id = rl.role_id
|
||||||
|
LEFT JOIN links l ON rl.link_id = l.id
|
||||||
|
WHERE u.email = @email
|
||||||
|
ORDER BY l.id",
|
||||||
|
new { email });
|
||||||
|
|
||||||
|
if (!userData.Any())
|
||||||
|
{
|
||||||
|
return Results.NotFound(new { detail = "User not found in database" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstRecord = userData.First();
|
||||||
|
var organization = firstRecord.OrgId.HasValue && firstRecord.OrgName != null
|
||||||
|
? new Organization(firstRecord.OrgId.Value, firstRecord.OrgName)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
var roles = userData
|
||||||
|
.Where(x => x.RoleId.HasValue)
|
||||||
|
.GroupBy(x => x.RoleId)
|
||||||
|
.Select(g => g.First())
|
||||||
|
.Select(x => new Role(x.RoleId!.Value, x.RoleName!, x.RoleDescription))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var links = userData
|
||||||
|
.Where(x => x.LinkId.HasValue)
|
||||||
|
.GroupBy(x => x.LinkId)
|
||||||
|
.Select(g => g.First())
|
||||||
|
.Select(x => new Link(x.LinkId!.Value, x.LinkTitle!, x.LinkUrl!, x.LinkDescription))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return Results.Ok(new UserInfo(firstRecord.Email, firstRecord.FullName, organization, roles, links));
|
||||||
|
}
|
||||||
|
catch (NpgsqlException ex) when (ex.IsTransient)
|
||||||
|
{
|
||||||
|
return Results.Json(new { error = "Database temporarily unavailable" }, statusCode: 503);
|
||||||
|
}
|
||||||
|
catch (NpgsqlException)
|
||||||
|
{
|
||||||
|
return Results.Json(new { error = "Database error" }, statusCode: 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
static void ConfigureJwtAuthentication(IServiceCollection services, AppConfig config)
|
||||||
|
{
|
||||||
|
if (config.InsecureDevMode)
|
||||||
|
{
|
||||||
|
services.AddAuthentication("InsecureDev")
|
||||||
|
.AddScheme<AuthenticationSchemeOptions, InsecureDevAuthenticationHandler>("InsecureDev", _ => { });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = config.Issuer;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidIssuer = config.Issuer,
|
||||||
|
ValidateAudience = false,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ClockSkew = config.ClockSkew,
|
||||||
|
NameClaimType = config.NameClaimType,
|
||||||
|
RoleClaimType = config.RoleClaimType
|
||||||
|
};
|
||||||
|
|
||||||
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnTokenValidated = context =>
|
||||||
|
{
|
||||||
|
var nameClaim = context.Principal?.FindFirst(config.NameClaimType);
|
||||||
|
var emailClaim = context.Principal?.FindFirst(config.EmailClaimType);
|
||||||
|
|
||||||
|
if (nameClaim == null && emailClaim != null)
|
||||||
|
{
|
||||||
|
var identity = context.Principal?.Identity as ClaimsIdentity;
|
||||||
|
identity?.AddClaim(new Claim(config.NameClaimType, emailClaim.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var httpClientHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
|
||||||
|
};
|
||||||
|
|
||||||
|
var discoveryUrl = $"{config.Issuer}.well-known/openid-configuration";
|
||||||
|
|
||||||
|
options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
|
||||||
|
discoveryUrl,
|
||||||
|
new OpenIdConnectConfigurationRetriever(),
|
||||||
|
new HttpDocumentRetriever(new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
RequireHttps = !config.InsecureDevMode
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ValidateConfiguration(AppConfig config)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(config.DbHost))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:DbHost' is required");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(config.DbPort))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:DbPort' is required");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(config.DbName))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:DbName' is required");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(config.DbUser))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:DbUser' is required");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(config.DbPassword))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:DbPassword' is required");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(config.Issuer))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:Issuer' is required");
|
||||||
|
|
||||||
|
if (!Uri.TryCreate(config.Issuer, UriKind.Absolute, out _))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:Issuer' must be a valid URL");
|
||||||
|
|
||||||
|
if (config.InsecureDevMode && string.IsNullOrWhiteSpace(config.InsecureDevEmail))
|
||||||
|
throw new InvalidOperationException("Configuration parameter 'AppConfig:InsecureDevEmail' is required when 'AppConfig:InsecureDevMode' is enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Task<string> GetUserEmail(HttpContext context, AppConfig config)
|
||||||
|
{
|
||||||
|
if (context.User.Identity?.IsAuthenticated == true)
|
||||||
|
{
|
||||||
|
var emailClaim = context.User.FindFirst(config.EmailClaimType);
|
||||||
|
if (emailClaim != null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(emailClaim.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.Request.Headers.TryGetValue(config.AuthRequestEmailHeader, out var emailHeader))
|
||||||
|
{
|
||||||
|
return Task.FromResult(emailHeader.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnauthorizedAccessException("No authentication information found");
|
||||||
|
}
|
||||||
|
|
||||||
|
record UserDataResult(
|
||||||
|
string Email,
|
||||||
|
string FullName,
|
||||||
|
int? OrgId,
|
||||||
|
string? OrgName,
|
||||||
|
int? RoleId,
|
||||||
|
string? RoleName,
|
||||||
|
string? RoleDescription,
|
||||||
|
int? LinkId,
|
||||||
|
string? LinkTitle,
|
||||||
|
string? LinkUrl,
|
||||||
|
string? LinkDescription
|
||||||
|
);
|
||||||
|
|
||||||
|
// API Response Models
|
||||||
|
record HealthResponse(string Status);
|
||||||
|
|
||||||
|
record ClaimResponse(string Type, string Value);
|
||||||
|
|
||||||
|
record UserIdentityResponse(
|
||||||
|
string? Name,
|
||||||
|
bool IsAuthenticated,
|
||||||
|
string? AuthenticationType,
|
||||||
|
List<ClaimResponse> Claims
|
||||||
|
);
|
||||||
53
backend-dotnet/README.md
Normal file
53
backend-dotnet/README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# .NET 8 Backend
|
||||||
|
|
||||||
|
Функционально эквивалентный бэкенд на .NET 8 для Dex Demo.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
### Локально
|
||||||
|
```bash
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
```bash
|
||||||
|
docker build -t dex-demo-backend-dotnet:latest .
|
||||||
|
docker run -p 8000:8000 \
|
||||||
|
-e AppConfig__DbHost=postgres \
|
||||||
|
-e AppConfig__DbPort=5440 \
|
||||||
|
-e AppConfig__Issuer=https://dex.127.0.0.1.sslip.io/ \
|
||||||
|
dex-demo-backend-dotnet:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Особенности реализации
|
||||||
|
|
||||||
|
- **Minimal APIs**: современный подход ASP.NET Core без лишнего бойлерплейта
|
||||||
|
- **Records**: для моделей данных (immutable, concise)
|
||||||
|
- **Dapper**: микро-ORM для чистой и производительной работы с БД
|
||||||
|
- **Npgsql**: официальный PostgreSQL provider для .NET
|
||||||
|
- **OpenIdConnect**: стандартный механизм получения JWKS
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
- `GET /api/health` - проверка здоровья
|
||||||
|
- `GET /api/user-info` - информация о пользователе (требует авторизацию)
|
||||||
|
|
||||||
|
## Переменные окружения
|
||||||
|
|
||||||
|
### База данных
|
||||||
|
- `AppConfig__DbHost` - хост PostgreSQL (по умолчанию: postgres)
|
||||||
|
- `AppConfig__DbPort` - порт PostgreSQL (по умолчанию: 5440)
|
||||||
|
- `AppConfig__DbName` - имя базы данных (по умолчанию: dexdemo)
|
||||||
|
- `AppConfig__DbUser` - пользователь базы данных (по умолчанию: dexdemo)
|
||||||
|
- `AppConfig__DbPassword` - пароль базы данных (по умолчанию: dexdemo)
|
||||||
|
|
||||||
|
### Аутентификация
|
||||||
|
- `AppConfig__Issuer` - URL Dex сервера (по умолчанию: https://dex.127.0.0.1.sslip.io/)
|
||||||
|
|
||||||
|
### Режим разработки
|
||||||
|
- `AppConfig__InsecureDevMode` - включить небезопасный режим разработки (true/false)
|
||||||
|
- `AppConfig__InsecureDevEmail` - email для тестирования в режиме разработки
|
||||||
|
|
||||||
|
### CORS
|
||||||
|
- `AppConfig__AllowedOrigins` - разрешенные origins для CORS (JSON массив)
|
||||||
|
|
||||||
30
backend-dotnet/appsettings.Development.json
Normal file
30
backend-dotnet/appsettings.Development.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authentication": "Trace",
|
||||||
|
"Microsoft.AspNetCore.Authorization": "Trace",
|
||||||
|
"Microsoft.IdentityModel": "Trace",
|
||||||
|
"System.Net.Http.HttpClient": "Trace",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer": "Trace",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler": "Trace",
|
||||||
|
"Microsoft.AspNetCore.Authorization.AuthorizationMiddleware": "Trace",
|
||||||
|
"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService": "Trace",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Urls": "http://localhost:8000",
|
||||||
|
"AppConfig": {
|
||||||
|
"DbHost": "localhost",
|
||||||
|
"DbPort": "5432",
|
||||||
|
"DbName": "dexdemo",
|
||||||
|
"DbUser": "dexdemo",
|
||||||
|
"DbPassword": "dexdemo",
|
||||||
|
"Issuer": "https://dex.127.0.0.1.sslip.io/",
|
||||||
|
"InsecureDevMode": true,
|
||||||
|
"InsecureDevEmail": "test@example.com",
|
||||||
|
"AllowedOrigins": ["http://localhost:3000", "https://localhost:3000", "http://localhost:5173", "https://localhost:5173"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
30
backend-dotnet/appsettings.Production.json
Normal file
30
backend-dotnet/appsettings.Production.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore.Authentication": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Authorization": "Warning",
|
||||||
|
"Microsoft.IdentityModel": "Warning",
|
||||||
|
"System.Net.Http.HttpClient": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer": "Information",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler": "Information",
|
||||||
|
"Microsoft.AspNetCore.Authorization.AuthorizationMiddleware": "Information",
|
||||||
|
"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService": "Information",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"AppConfig": {
|
||||||
|
"DbHost": "postgres",
|
||||||
|
"DbPort": "5432",
|
||||||
|
"DbName": "dexdemo",
|
||||||
|
"DbUser": "dexdemo",
|
||||||
|
"DbPassword": "dexdemo",
|
||||||
|
"Issuer": "https://dex.127.0.0.1.sslip.io/",
|
||||||
|
"InsecureDevMode": false,
|
||||||
|
"AllowedOrigins": ["https://yourdomain.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
28
backend-dotnet/appsettings.json
Normal file
28
backend-dotnet/appsettings.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authentication": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authorization": "Debug",
|
||||||
|
"Microsoft.IdentityModel": "Debug",
|
||||||
|
"System.Net.Http.HttpClient": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authorization.AuthorizationMiddleware": "Debug",
|
||||||
|
"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService": "Debug",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"AppConfig": {
|
||||||
|
"DbHost": "postgres",
|
||||||
|
"DbPort": "5440",
|
||||||
|
"DbName": "dexdemo",
|
||||||
|
"DbUser": "dexdemo",
|
||||||
|
"DbPassword": "dexdemo",
|
||||||
|
"Issuer": "https://dex.127.0.0.1.sslip.io/",
|
||||||
|
"InsecureDevMode": false,
|
||||||
|
"AllowedOrigins": ["http://localhost:3000", "https://localhost:3000"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
19
backend-dotnet/backend-dotnet.csproj
Normal file
19
backend-dotnet/backend-dotnet.csproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<RootNamespace>DexDemoBackend</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
|
||||||
|
<PackageReference Include="Npgsql" Version="8.0.7" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
||||||
Reference in New Issue
Block a user