сделал авторизацию и регестрацию. Роли сломаны
This commit is contained in:
parent
f7f0a56c51
commit
304e7bf5f5
4
.gitignore
vendored
4
.gitignore
vendored
@ -47,6 +47,8 @@ bld/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
Migrations/
|
||||
VolumeMount.AppHost-postgresql-data/
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
@ -69,6 +71,8 @@ nunit-*.xml
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
VolumeMount.AppHost-postgresql-data/
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
public static class DbHelpersEndpointsExtensions
|
||||
{
|
||||
public static RouteGroupBuilder AddDbHelpersEndpoints(this WebApplication app)
|
||||
{
|
||||
var group = app.MapGroup("/db");
|
||||
|
||||
group.MapPost("/migrate/{contexClassName}", async (string contexClasstName, IServiceProvider services) =>
|
||||
{
|
||||
var contextType = typeof(Program).Assembly.GetType(contexClasstName);
|
||||
|
||||
if(contextType is null)
|
||||
return Results.NotFound();
|
||||
|
||||
var inheritanceChain = contextType.GetInheritanceChain();
|
||||
|
||||
if(!inheritanceChain.Any(t => typeof(DbContext) == t))
|
||||
return Results.NotFound();
|
||||
|
||||
|
||||
using var scope = services.CreateScope();
|
||||
|
||||
var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType);
|
||||
|
||||
await dbContext.Database.MigrateAsync();
|
||||
return Results.Ok();
|
||||
});
|
||||
|
||||
group.MapPost("/initdb/{contexClassName}", async (string contexClasstName, IServiceProvider services) =>
|
||||
{
|
||||
var contextType = typeof(Program).Assembly.GetType(contexClasstName);
|
||||
|
||||
if(contextType is null)
|
||||
return Results.NotFound();
|
||||
|
||||
var inheritanceChain = contextType.GetInheritanceChain();
|
||||
|
||||
if(!inheritanceChain.Any(t => typeof(DbContext) == t))
|
||||
return Results.NotFound();
|
||||
|
||||
|
||||
using var scope = services.CreateScope();
|
||||
|
||||
var dbContext = (DbContext)scope.ServiceProvider.GetRequiredService(contextType);
|
||||
|
||||
await dbContext.Database.EnsureCreatedAsync();
|
||||
return Results.Ok();
|
||||
});
|
||||
|
||||
group.MapPost("/add-moderator", async ([FromServices]UserManager<User> userManager) => {
|
||||
var user = new User{
|
||||
Email = "m@gmail.com",
|
||||
UserName = "m@gmail.com"
|
||||
};
|
||||
var result = await userManager.CreateAsync(user, "PassPass123_");
|
||||
|
||||
if(!result.Succeeded)
|
||||
return Results.BadRequest(result.Errors);
|
||||
|
||||
var roleResult = await userManager.AddToRoleAsync(user, "moderator");
|
||||
|
||||
if(!roleResult.Succeeded)
|
||||
return Results.BadRequest(roleResult.Errors);
|
||||
|
||||
return Results.Ok(new {
|
||||
Login = "m@gmail.com",
|
||||
Password = "PassPass123_",
|
||||
Role = "moderator"
|
||||
});
|
||||
}).WithDescription($"Create user with login/email/username: m@gmail.com and password: PassPass123_");
|
||||
|
||||
group.WithTags("db");
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public static class ServicesExtensions
|
||||
{
|
||||
|
||||
public static void AddDbContextWithDefaultConfiguration<TDbContext>(this WebApplicationBuilder builder) where TDbContext : DbContext
|
||||
{
|
||||
builder.AddNpgsqlDbContext<TDbContext>("prod", null,
|
||||
optionsBuilder => optionsBuilder.UseNpgsql(npgsqlBuilder =>
|
||||
npgsqlBuilder.MigrationsAssembly(typeof(Program).Assembly.GetName().Name)));
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
@ -1,5 +1,5 @@
|
||||
using HackathonPreparing.ApiService;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@ -7,90 +7,78 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo {
|
||||
Title = "Weather Forecast API",
|
||||
Description = "Weather forecast API for the HackathonPreparing project.",
|
||||
Version = "v1" });
|
||||
c.SchemaFilter<UserOpenApiSchemeFilter>();
|
||||
c.AddSecurityDefinition("AccessToken", new OpenApiSecurityScheme {
|
||||
In = ParameterLocation.Header,
|
||||
Description = "can get in /login or /register",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.Http,
|
||||
BearerFormat = "JWT",
|
||||
Scheme = "bearer"
|
||||
});
|
||||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement{
|
||||
{
|
||||
new OpenApiSecurityScheme {
|
||||
Reference = new OpenApiReference{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "AccessToken"
|
||||
}
|
||||
},
|
||||
new string[]{}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add service defaults & Aspire components.
|
||||
builder.AddServiceDefaults();
|
||||
//we dont need it now
|
||||
//builder.AddServiceDefaults();
|
||||
|
||||
|
||||
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.AddPolicy("moderator", policy =>
|
||||
policy.RequireRole("MODERATOR"));
|
||||
|
||||
//TODO BEARER
|
||||
builder.Services.AddAuthentication().AddBearerToken(IdentityConstants.BearerScheme);
|
||||
|
||||
builder.Services.AddIdentity<User, IdentityRole<int>>()
|
||||
.AddEntityFrameworkStores<UserContext>()
|
||||
.AddApiEndpoints();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddProblemDetails();
|
||||
|
||||
builder.AddNpgsqlDbContext<DatabaseContext>("prod", null,
|
||||
optionsBuilder => optionsBuilder.UseNpgsql(npgsqlBuilder =>
|
||||
npgsqlBuilder.MigrationsAssembly(typeof(Program).Assembly.GetName().Name)));
|
||||
builder.AddDbContextWithDefaultConfiguration<WeatherForecastContext>();
|
||||
builder.AddDbContextWithDefaultConfiguration<UserContext>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||
app.UsePathBase(new PathString("/api"));
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogWarning("!!!!!!! Call /ensure-created enpoint or /migrate if no db !!!!!!!!");
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Weather Forecast API V1");
|
||||
});
|
||||
app.MapGet("/ensure-created", async (DatabaseContext db) => await db.Database.EnsureCreatedAsync());
|
||||
|
||||
app.MapGet("/migrate", async (DatabaseContext db) => await db.Database.MigrateAsync());
|
||||
app.UseSwaggerUI();
|
||||
app.AddDbHelpersEndpoints();
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
app.UseExceptionHandler();
|
||||
app.UseAuthorization();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.MapGet("/weatherforecast", async (DatabaseContext db) => await db.Forecasts.ToListAsync());
|
||||
app.MapDelete("/weatherforecast/{id}", async (DatabaseContext db, int id) =>
|
||||
{
|
||||
var forecast = await db.Forecasts.FindAsync(id);
|
||||
if (forecast == null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
db.Forecasts.Remove(forecast);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.NoContent();
|
||||
});
|
||||
app.MapPost("/weatherforecast", async (DatabaseContext db, WeatherForecast forecast) =>
|
||||
{
|
||||
db.Forecasts.Add(forecast);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Created($"/weatherforecast/{forecast.Id}", forecast);
|
||||
});
|
||||
app.MapPut("/weatherforecast/{id}", async (DatabaseContext db, int id, WeatherForecast forecast) =>
|
||||
{
|
||||
if (id != forecast.Id)
|
||||
{
|
||||
return Results.BadRequest();
|
||||
}
|
||||
|
||||
db.Entry(forecast).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (await db.Forecasts.FindAsync(id) == null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return Results.NoContent();
|
||||
});
|
||||
|
||||
app.AddWeatherForecastEndpoints();
|
||||
|
||||
app.MapDefaultEndpoints();
|
||||
|
||||
app.MapGroup("/user")
|
||||
.MapIdentityApi<User>()
|
||||
.WithTags("user");
|
||||
|
||||
app.Run();
|
||||
|
@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
public class IdentityRoleEntityTypeConfiguration : IEntityTypeConfiguration<IdentityRole<int>>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<IdentityRole<int>> builder)
|
||||
{
|
||||
builder.HasData(
|
||||
[
|
||||
new IdentityRole<int>{
|
||||
Id = 1,
|
||||
Name = "moderator",
|
||||
NormalizedName = "MODERATOR",
|
||||
ConcurrencyStamp = Guid.NewGuid().ToString()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
|
||||
//Example how add Fluent Building in project
|
||||
public class UserEntityTypeConfiguration : IEntityTypeConfiguration<User>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<User> builder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
public class User : IdentityUser<int>
|
||||
{
|
||||
public string? AboutMe { get; set; }
|
||||
|
||||
public override bool TwoFactorEnabled => false;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public class UserContext : IdentityDbContext<User, IdentityRole<int>, int>
|
||||
{
|
||||
public UserContext (DbContextOptions<UserContext> options) : base(options) {}
|
||||
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
builder.ApplyConfigurationsFromAssembly(typeof(Program).Assembly);
|
||||
builder.HasDefaultSchema("user");
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
using HackathonPreparing.ApiService.Migrations;
|
||||
using Microsoft.AspNetCore.Identity.Data;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
public class UserOpenApiSchemeFilter : ISchemaFilter
|
||||
{
|
||||
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
||||
{
|
||||
if (context.Type == typeof(LoginRequest))
|
||||
{
|
||||
schema.Example = new OpenApiObject()
|
||||
{
|
||||
["email"] = new OpenApiString("email@gmail.com"),
|
||||
["password"] = new OpenApiString("PassPass123_"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (context.Type == typeof(RegisterRequest))
|
||||
{
|
||||
schema.Example = new OpenApiObject()
|
||||
{
|
||||
["email"] = new OpenApiString("email@gmail.com"),
|
||||
["password"] = new OpenApiString("PassPass123_"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HackathonPreparing.ApiService.User
|
||||
{
|
||||
public class UserController : Controller
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
namespace HackathonPreparing.ApiService;
|
||||
|
||||
public class WeatherForecast
|
||||
{
|
||||
public WeatherForecast(int id, DateOnly date, int temperatureC, string summary)
|
||||
{
|
||||
Id = id;
|
||||
Date = date;
|
||||
TemperatureC = temperatureC;
|
||||
Summary = summary;
|
||||
}
|
||||
|
||||
|
||||
public int Id { get; set; }
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string Summary { get; set; }
|
||||
}
|
@ -2,9 +2,9 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HackathonPreparing.ApiService;
|
||||
|
||||
public sealed class DatabaseContext : DbContext
|
||||
public sealed class WeatherForecastContext : DbContext
|
||||
{
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> options)
|
||||
public WeatherForecastContext(DbContextOptions<WeatherForecastContext> options)
|
||||
: base(options)
|
||||
{
|
||||
|
||||
@ -39,20 +39,3 @@ public sealed class DatabaseContext : DbContext
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public class WeatherForecast
|
||||
{
|
||||
public WeatherForecast(int id, DateOnly date, int temperatureC, string summary)
|
||||
{
|
||||
Id = id;
|
||||
Date = date;
|
||||
TemperatureC = temperatureC;
|
||||
Summary = summary;
|
||||
}
|
||||
|
||||
|
||||
public int Id { get; set; }
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string Summary { get; set; }
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
|
||||
using HackathonPreparing.ApiService;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public static class WeatherForecastExtensions
|
||||
{
|
||||
public static void AddWeatherForecastEndpoints (this WebApplication app)
|
||||
{
|
||||
var group = app.MapGroup("/weatherforecast");
|
||||
group.MapGet("/", async (WeatherForecastContext db) => await db.Forecasts.ToListAsync());
|
||||
group.MapDelete("/{id}", async (WeatherForecastContext db, int id) =>
|
||||
{
|
||||
var forecast = await db.Forecasts.FindAsync(id);
|
||||
if (forecast == null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
db.Forecasts.Remove(forecast);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.NoContent();
|
||||
}).RequireAuthorization("moderator");
|
||||
group.MapPost("/", async (WeatherForecastContext db, WeatherForecast forecast) =>
|
||||
{
|
||||
db.Forecasts.Add(forecast);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Created($"/weatherforecast/{forecast.Id}", forecast);
|
||||
});
|
||||
group.MapPut("/{id}", async (WeatherForecastContext db, int id, WeatherForecast forecast) =>
|
||||
{
|
||||
if (id != forecast.Id)
|
||||
{
|
||||
return Results.BadRequest();
|
||||
}
|
||||
|
||||
db.Entry(forecast).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (await db.Forecasts.FindAsync(id) == null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return Results.NoContent();
|
||||
}).RequireAuthorization("moderator");
|
||||
group.WithTags("weatherforecast");
|
||||
}
|
||||
}
|
@ -1,9 +1,26 @@
|
||||
|
||||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
//use it
|
||||
//dotnet user-secrets set Parameters:postgresql-password _StroNG_PaSSworD_
|
||||
//dotnet user-secrets set Parameters:postgresql-username dev_user
|
||||
|
||||
//.WithBindMount("VolumeMount.AppHost-postgresql-data", "/var/lib/postgresql/data")
|
||||
|
||||
var cache = builder.AddRedis("cache");
|
||||
|
||||
var postgres = builder.AddPostgres("postgres").WithPgAdmin();
|
||||
var postgresdb = postgres.AddDatabase("prod");
|
||||
var sqlPassword = builder.AddParameter("postgresql-password", secret: true);
|
||||
|
||||
var sqlUser = builder.AddParameter("postgresql-username", secret: true);
|
||||
|
||||
var postgresdb = builder
|
||||
//.AddPostgres("postgres", password: sqlPassword, userName: sqlUser)
|
||||
.AddPostgres("postgres")
|
||||
.WithPgAdmin()
|
||||
//.WithDataVolume()
|
||||
.AddDatabase("prod");
|
||||
|
||||
|
||||
var apiService = builder.AddProject<Projects.HackathonPreparing_ApiService>("apiservice").WithReference(postgresdb);
|
||||
|
||||
builder.AddProject<Projects.HackathonPreparing_Web>("webfrontend")
|
||||
|
Loading…
x
Reference in New Issue
Block a user