Skip to content

Commit

Permalink
Svelte website: login and logout (#835)
Browse files Browse the repository at this point in the history
- Implement login button and baas auth
- Reserve /api for website data endpoints. Example included with
functional validation of idToken cookie, but not used yet
  • Loading branch information
SapiensAnatis authored May 26, 2024
1 parent 8a0d8c9 commit 8e74d2a
Show file tree
Hide file tree
Showing 54 changed files with 1,232 additions and 726 deletions.
147 changes: 75 additions & 72 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,80 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AutoMapper" Version="12.0.1"/>
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1"/>
<PackageVersion Include="Basic.Reference.Assemblies" Version="1.7.2"/>
<PackageVersion Include="EntityGraphQL" Version="5.2.1"/>
<PackageVersion Include="EntityGraphQL.AspNet" Version="5.2.1"/>
<PackageVersion Include="FluentRandomPicker" Version="3.5.1"/>
<PackageVersion Include="FluentValidation" Version="11.9.1"/>
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.12"/>
<PackageVersion Include="Hangfire.Core" Version="1.8.12"/>
<PackageVersion Include="Hangfire.Postgresql" Version="1.20.8"/>
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0"/>
<PackageVersion Include="MessagePack" Version="2.5.140"/>
<PackageVersion Include="MessagePack.AspNetCoreMvcFormatter" Version="2.5.140"/>
<PackageVersion Include="MessagePackAnalyzer" Version="2.5.140"/>
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.5"/>
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.3"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2"/>
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.5"/>
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.5"/>
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.5.0"/>
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4"/>
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4"/>
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5"/>
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.5"/>
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1"/>
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.5"/>
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1"/>
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="7.5.1"/>
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1"/>
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.2"/>
<PackageVersion Include="MudBlazor" Version="6.19.1"/>
<PackageVersion Include="PolySharp" Version="1.14.1"/>
<PackageVersion Include="Riok.Mapperly" Version="3.5.0-next.1"/>
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0"/>
<PackageVersion Include="Serilog.Expressions" Version="4.0.0"/>
<PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.0"/>
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0"/>
<PackageVersion Include="Serilog.Sinks.Seq" Version="7.0.0"/>
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1"/>
<PackageVersion Include="System.Text.Json" Version="8.0.3"/>
<PackageVersion Include="Serilog" Version="3.1.1"/>
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.1"/>
<PackageVersion Include="Serilog.Sinks.Console" Version="5.0.1"/>
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0"/>
<PackageVersion Include="FluentAssertions" Version="6.12.0"/>
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.5"/>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageVersion Include="MockQueryable.Moq" Version="7.0.1"/>
<PackageVersion Include="Moq" Version="4.20.70"/>
<PackageVersion Include="Verify.SourceGenerators" Version="2.2.0"/>
<PackageVersion Include="Verify.XUnit" Version="24.1.0"/>
<PackageVersion Include="xunit" Version="2.7.1"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.0"/>
<PackageVersion Include="GraphQL.Client" Version="6.0.2"/>
<PackageVersion Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.0.3"/>
<PackageVersion Include="MartinCostello.Logging.XUnit" Version="0.3.0"/>
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.2"/>
<PackageVersion Include="Respawn" Version="6.2.1"/>
<PackageVersion Include="Snapshooter.Xunit" Version="0.14.1"/>
<PackageVersion Include="Testcontainers" Version="3.7.0"/>
<PackageVersion Include="Testcontainers.PostgreSql" Version="3.7.0"/>
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.5"/>
<PackageVersion Include="Moq.EntityFrameworkCore" Version="8.0.1.2"/>
<PackageVersion Include="NSubstitute" Version="5.1.0"/>
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17"/>
<PackageVersion Include="Redis.OM" Version="0.6.1"/>
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5"/>
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0"/>
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0"/>
<PackageVersion Include="AutoMapper" Version="12.0.1" />
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageVersion Include="Basic.Reference.Assemblies" Version="1.7.2" />
<PackageVersion Include="EntityGraphQL" Version="5.2.1" />
<PackageVersion Include="EntityGraphQL.AspNet" Version="5.2.1" />
<PackageVersion Include="FluentRandomPicker" Version="3.5.1" />
<PackageVersion Include="FluentValidation" Version="11.9.1" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.12" />
<PackageVersion Include="Hangfire.Core" Version="1.8.12" />
<PackageVersion Include="Hangfire.Postgresql" Version="1.20.8" />
<PackageVersion Include="Immediate.Apis" Version="1.1.0" />
<PackageVersion Include="Immediate.Handlers" Version="1.4.0" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageVersion Include="MessagePack" Version="2.5.140" />
<PackageVersion Include="MessagePack.AspNetCoreMvcFormatter" Version="2.5.140" />
<PackageVersion Include="MessagePackAnalyzer" Version="2.5.140" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.5.0" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.5" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="7.5.1" />
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.2" />
<PackageVersion Include="MudBlazor" Version="6.19.1" />
<PackageVersion Include="PolySharp" Version="1.14.1" />
<PackageVersion Include="Riok.Mapperly" Version="3.5.0-next.1" />
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
<PackageVersion Include="Serilog.Expressions" Version="4.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<PackageVersion Include="System.Text.Json" Version="8.0.3" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageVersion Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.5" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="MockQueryable.Moq" Version="7.0.1" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="Verify.SourceGenerators" Version="2.2.0" />
<PackageVersion Include="Verify.XUnit" Version="24.1.0" />
<PackageVersion Include="xunit" Version="2.7.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.0" />
<PackageVersion Include="GraphQL.Client" Version="6.0.2" />
<PackageVersion Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.0.3" />
<PackageVersion Include="MartinCostello.Logging.XUnit" Version="0.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.2" />
<PackageVersion Include="Respawn" Version="6.2.1" />
<PackageVersion Include="Snapshooter.Xunit" Version="0.14.1" />
<PackageVersion Include="Testcontainers" Version="3.7.0" />
<PackageVersion Include="Testcontainers.PostgreSql" Version="3.7.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.5" />
<PackageVersion Include="Moq.EntityFrameworkCore" Version="8.0.1.2" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
<PackageVersion Include="Redis.OM" Version="0.6.1" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
</Project>
22 changes: 16 additions & 6 deletions DragaliaAPI/DragaliaAPI.Database/DatabaseConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
using DragaliaAPI.Database.Repositories;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

[assembly: InternalsVisibleTo("DragaliaAPI.Database.Test")]
[assembly: InternalsVisibleTo("DragaliaAPI.Test")]
Expand All @@ -18,14 +20,22 @@ public static class DatabaseConfiguration

public static IServiceCollection ConfigureDatabaseServices(
this IServiceCollection services,
PostgresOptions postgresOptions
IConfiguration config
)
{
services = services
.AddDbContext<ApiContext>(options =>
options
.UseNpgsql(postgresOptions.GetConnectionString("ApiContext"))
.EnableDetailedErrors()
services.Configure<PostgresOptions>(config.GetRequiredSection(nameof(PostgresOptions)));

services
.AddDbContext<ApiContext>(
(serviceProvider, options) =>
{
PostgresOptions postgresOptions = serviceProvider
.GetRequiredService<IOptions<PostgresOptions>>()
.Value;
options
.UseNpgsql(postgresOptions.GetConnectionString("ApiContext"))
.EnableDetailedErrors();
}
)
#pragma warning disable CS0618 // Type or member is obsolete
.AddScoped<IDeviceAccountRepository, DeviceAccountRepository>()
Expand Down
5 changes: 4 additions & 1 deletion DragaliaAPI/DragaliaAPI.Integration.Test/TestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ protected HttpClient CreateClient(Action<IWebHostBuilder>? extraBuilderConfig =
.CreateClient(
new WebApplicationFactoryClientOptions()
{
BaseAddress = new Uri("http://localhost/api/", UriKind.Absolute),
BaseAddress = new Uri(
"http://localhost/2.19.0_20220714193707/",
UriKind.Absolute
),
}
);

Expand Down
3 changes: 3 additions & 0 deletions DragaliaAPI/DragaliaAPI/DragaliaAPI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
<PackageReference Include="Hangfire.AspNetCore" />
<PackageReference Include="Hangfire.Core" />
<PackageReference Include="Hangfire.Postgresql" />
<PackageReference Include="Immediate.Apis" />
<PackageReference Include="Immediate.Handlers" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="MessagePack" />
<PackageReference Include="MessagePack.AspNetCoreMvcFormatter" />
<PackageReference Include="MessagePackAnalyzer">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
Expand Down
29 changes: 29 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/Web/ConfigureJwtBearerOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using DragaliaAPI.Models.Options;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;

namespace DragaliaAPI.Features.Web;

/// <summary>
/// Allows setting additional properties on <see cref="JwtBearerOptions"/> using DI.
/// </summary>
/// <remarks>
/// Sourced from: <see href="https://gist.github.com/xiaomi7732/20ff2ad11b085a851759d3835b95c8d7"/>
/// </remarks>
public class ConfigureJwtBearerOptions(IOptions<BaasOptions> baasOptions)
: IConfigureNamedOptions<JwtBearerOptions>
{
// Never called
public void Configure(JwtBearerOptions options) =>
this.Configure(JwtBearerDefaults.AuthenticationScheme, options);

public void Configure(string? name, JwtBearerOptions options)
{
options.Authority = baasOptions.Value.BaasUrl;
options.TokenValidationParameters = new()
{
ValidAudience = baasOptions.Value.TokenAudience,
ValidIssuer = baasOptions.Value.TokenIssuer,
};
}
}
43 changes: 43 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/Web/FeatureExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using DragaliaAPI.Features.Web;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;

// ReSharper disable once CheckNamespace
namespace DragaliaAPI;

public static partial class FeatureExtensions
{
public static IServiceCollection AddWebFeature(this IServiceCollection serviceCollection)
{
serviceCollection
.AddTransient<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>()
.AddScoped<UserService>();

serviceCollection
.AddAuthentication()
.AddJwtBearer(
WebAuthenticationHelper.SchemeName,
opts =>
{
opts.Events = new()
{
OnMessageReceived = WebAuthenticationHelper.OnMessageReceived,
OnTokenValidated = WebAuthenticationHelper.OnTokenValidated
};
// The rest is configured in ConfigureJwtBearerOptions.cs after the ServiceProvider is built.
}
);

serviceCollection
.AddAuthorizationBuilder()
.AddPolicy(
WebAuthenticationHelper.PolicyName,
builder =>
builder
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(WebAuthenticationHelper.SchemeName)
);

return serviceCollection;
}
}
19 changes: 19 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/Web/UserQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Immediate.Apis.Shared;
using Immediate.Handlers.Shared;
using Microsoft.AspNetCore.Authorization;

namespace DragaliaAPI.Features.Web;

[Handler]
[MapGet("/api/user")]
[Authorize(WebAuthenticationHelper.PolicyName)]
public static partial class UserQuery
{
public record Query;

private static async ValueTask<User> HandleAsync(
Query _,
UserService userService,
CancellationToken cancellationToken
) => await userService.GetUser(cancellationToken);
}
21 changes: 21 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/Web/UserService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using DragaliaAPI.Database;
using DragaliaAPI.Shared.PlayerDetails;
using Microsoft.EntityFrameworkCore;

namespace DragaliaAPI.Features.Web;

public class UserService(IPlayerIdentityService playerIdentityService, ApiContext apiContext)
{
public Task<User> GetUser(CancellationToken cancellationToken) =>
apiContext
.Players.Where(x => x.ViewerId == playerIdentityService.ViewerId)
.Select(x => new User() { Name = x.UserData!.Name, ViewerId = x.ViewerId, })
.FirstAsync(cancellationToken);
}

public class User
{
public long ViewerId { get; init; }

public required string Name { get; init; }
}
Loading

0 comments on commit 8e74d2a

Please sign in to comment.