/
rumina-v
/
auth_validation
Обзор
Документация
Войти
/
rumina-v
/
auth_validation
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Program.cs
208 строк
6 KB
Viktoria Rumina
Add solution files
04 июн 2026, 12:13
04 июн 2026, 12:13
90cb0b2
Код
Авторство
О чём код?
using System.Security.Claims; using System.Text; using FluentValidation; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); var jwtSettings = builder.Configuration.GetSection(JwtSettings.SectionName) .Get<JwtSettings>() ?? throw new InvalidOperationException("JWT settings are missing."); builder.Services.Configure<JwtSettings>( builder.Configuration.GetSection(JwtSettings.SectionName)); builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped<IPasswordHasher<UserAccount>, PasswordHasher<UserAccount>>(); builder.Services.AddScoped<JwtTokenService>(); builder.Services.AddValidatorsFromAssemblyContaining<Program>(); builder.Services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings.Issuer, ValidAudience = jwtSettings.Audience, IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(jwtSettings.Key)) }; }); builder.Services.AddAuthorization(options => { options.AddPolicy(AuthPolicies.ManageNotes, policy => policy.RequireRole(AuthClaims.MemberRole) .RequireClaim(AuthClaims.Permission, AuthClaims.ManageNotes)); options.AddPolicy(AuthPolicies.EditProfile, policy => policy.RequireRole(AuthClaims.MemberRole) .RequireClaim(AuthClaims.Permission, AuthClaims.EditProfile)); }); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); dbContext.Database.EnsureCreated(); } app.UseAuthentication(); app.UseAuthorization(); app.MapGet("/", () => Results.Ok(new { message = "Auth Validation API is running", endpoints = new[] { "POST /api/auth/register", "POST /api/auth/login", "POST /api/notes", "PUT /api/profile" } })); app.MapPost("/api/auth/register", async ( RegisterRequest request, IValidator<RegisterRequest> validator, IPasswordHasher<UserAccount> passwordHasher, AppDbContext dbContext) => { var validationProblem = await validator.ValidateAsProblemAsync(request); if (validationProblem is not null) { return validationProblem; } var normalizedEmail = request.Email.Trim().ToUpperInvariant(); if (await dbContext.Users.AnyAsync(user => user.NormalizedEmail == normalizedEmail)) { return Results.ValidationProblem(new Dictionary<string, string[]> { [nameof(request.Email)] = ["A user with this email already exists."] }); } var user = new UserAccount { Email = request.Email.Trim(), NormalizedEmail = normalizedEmail, DisplayName = request.DisplayName.Trim() }; user.PasswordHash = passwordHasher.HashPassword(user, request.Password); dbContext.Users.Add(user); await dbContext.SaveChangesAsync(); return Results.Created($"/api/users/{user.Id}", new { user.Id, user.Email, user.DisplayName }); }); app.MapPost("/api/auth/login", async ( LoginRequest request, IValidator<LoginRequest> validator, IPasswordHasher<UserAccount> passwordHasher, JwtTokenService tokenService, AppDbContext dbContext) => { var validationProblem = await validator.ValidateAsProblemAsync(request); if (validationProblem is not null) { return validationProblem; } var normalizedEmail = request.Email.Trim().ToUpperInvariant(); var user = await dbContext.Users.SingleOrDefaultAsync( item => item.NormalizedEmail == normalizedEmail); if (user is null) { return Results.Unauthorized(); } var verificationResult = passwordHasher.VerifyHashedPassword( user, user.PasswordHash, request.Password); if (verificationResult == PasswordVerificationResult.Failed) { return Results.Unauthorized(); } if (verificationResult == PasswordVerificationResult.SuccessRehashNeeded) { user.PasswordHash = passwordHasher.HashPassword(user, request.Password); await dbContext.SaveChangesAsync(); } return Results.Ok(tokenService.CreateToken(user)); }); app.MapPost("/api/notes", async ( CreateNoteRequest request, ClaimsPrincipal principal, IValidator<CreateNoteRequest> validator, AppDbContext dbContext) => { var validationProblem = await validator.ValidateAsProblemAsync(request); if (validationProblem is not null) { return validationProblem; } var note = new PersonalNote { UserId = principal.GetUserId(), Title = request.Title.Trim(), Text = request.Text.Trim(), Category = request.Category.Trim().ToLowerInvariant() }; dbContext.Notes.Add(note); await dbContext.SaveChangesAsync(); return Results.Created($"/api/notes/{note.Id}", note); }).RequireAuthorization(AuthPolicies.ManageNotes); app.MapPut("/api/profile", async ( UpdateProfileRequest request, ClaimsPrincipal principal, IValidator<UpdateProfileRequest> validator, AppDbContext dbContext) => { var validationProblem = await validator.ValidateAsProblemAsync(request); if (validationProblem is not null) { return validationProblem; } var user = await dbContext.Users.FindAsync(principal.GetUserId()); if (user is null) { return Results.NotFound(); } user.DisplayName = request.DisplayName.Trim(); user.Bio = request.Bio.Trim(); await dbContext.SaveChangesAsync(); return Results.Ok(new { user.Id, user.Email, user.DisplayName, user.Bio }); }).RequireAuthorization(AuthPolicies.EditProfile); app.Run();