Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements/moving files around #25

Merged
merged 36 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d1c79a1
Restructuring project and naming conventions
WorldWideWest Feb 28, 2024
d42714b
Adding google support
WorldWideWest Feb 29, 2024
2d81a13
Setting up providers for external auth
WorldWideWest Mar 1, 2024
479f1b2
Implementation for external auth providers
WorldWideWest Mar 1, 2024
fa1355d
Adding support for saving users from external identity provider
WorldWideWest Mar 1, 2024
de25b0d
Made it successfully to google consent screen
WorldWideWest Mar 1, 2024
cb2b12f
Attaching vs code debugger and updating google auth scheme, successfu…
WorldWideWest Mar 1, 2024
cbc5cfd
fixing bug with no user reported
WorldWideWest Mar 1, 2024
657bd0d
adding saving claims from result and finding identity provider dynami…
WorldWideWest Mar 1, 2024
a1ba320
Updating clients naming and controller
WorldWideWest Mar 1, 2024
5f04408
fixing naming in files and constants
WorldWideWest Mar 1, 2024
b481798
ADding comments on what to improve
WorldWideWest Mar 1, 2024
faa008c
Moved queries and commands from isv to identity
WorldWideWest Mar 2, 2024
b7e5f2f
Fixing bug in controller
WorldWideWest Mar 2, 2024
61f9b47
Updated isv extension (clients) to read more client config from confi…
WorldWideWest Mar 2, 2024
a05cf14
Fixing issues with provieder key saved in the place of userid and fix…
WorldWideWest Mar 3, 2024
a746343
Adding logut capability
WorldWideWest Mar 3, 2024
9dd9138
Renaming files and cleaning up the externallogincallback endpoint
WorldWideWest Mar 3, 2024
bf12d80
Refactoring and validating changes
WorldWideWest Mar 3, 2024
88dc1b4
Naming fix and adding error handling messages
WorldWideWest Mar 3, 2024
c1a9f54
Simplifying naming
WorldWideWest Mar 4, 2024
613d491
Trying to figure out why expired token not getting validated
WorldWideWest Mar 5, 2024
4eac29c
Rebuilding on change with develop.watch
WorldWideWest Mar 6, 2024
025d32a
Adding token validation params
WorldWideWest Mar 6, 2024
4e91242
Fixing comments with debugger and vscode config and logout flow simpl…
WorldWideWest Mar 6, 2024
6a62795
Updating api scope naming scheme for profile password
WorldWideWest Mar 6, 2024
f24ec1d
fixing comments
WorldWideWest Mar 6, 2024
a539148
Refactoring and deleting unnecessary code
WorldWideWest Mar 7, 2024
e87751a
Removed log
WorldWideWest Mar 7, 2024
676ec7e
Added prod dockerfile and docs and comments around the project
WorldWideWest Mar 7, 2024
188ac63
Fixing container name in launch.json
WorldWideWest Mar 7, 2024
2c63a6a
Deleted task.json
WorldWideWest Mar 7, 2024
a052eac
REmoving unnecessery usings
WorldWideWest Mar 7, 2024
fad0d5b
Refactoring
WorldWideWest Mar 7, 2024
9513a75
Changing const names for password policy and scope
WorldWideWest Mar 7, 2024
f8807f2
Changing error messages and removing prod ready dockerfile due to fut…
WorldWideWest Mar 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ project.lock.json
*.pyc
nupkg/

appsettings.Internal.json

# cert & key files
compose/nginx/certs
compose/nginx/keys
Expand Down
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Docker .NET Attach (Preview)",
"type": "docker",
"request": "attach",
"platform": "netCore",
"sourceFileMap": {
"/app": "${workspaceFolder}"
},
"processId": "${command:pickRemoteProcess}",
"containerName": "api",
},
]
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ This is implemented using GitHub Actions and the script can be found at `.github
| ✅ | Safely manage not awaited calls | [#22](https://github.com/WorldWideWest/dotnet-template/issues/22)
| ✅ | Global Error Handling | [#15](https://github.com/WorldWideWest/dotnet-template/issues/15)
| ❌ | Create an Actual .NET Project Template | [#16](https://github.com/WorldWideWest/dotnet-template/issues/16)
| ✅ | Adding External Login Provider support (Google) | )

2 changes: 1 addition & 1 deletion compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ docker-compose -f ./docker-compose.debug.amd.yml down && docker-compose -f ./doc
| Status of Implementation | Description | Issue |
| ----------- | ----------- |----------
| ✅ | Compose file for AMD64 architecture | [#12](https://github.com/WorldWideWest/dotnet-template/issues/12)
| | Debugging using VS Code Debugger | [#1](https://github.com/WorldWideWest/dotnet-template/issues/1)
| | Debugging using VS Code Debugger | [#1](https://github.com/WorldWideWest/dotnet-template/issues/1)
| ✅ | Startup Script that generates SSL certificates and runs the dotnet watch command | [#14](https://github.com/WorldWideWest/dotnet-template/issues/14)
5 changes: 5 additions & 0 deletions compose/docker-compose.debug.amd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ services:
timeout: 10s
retries: 5
start_period: 10s
develop:
watch:
- path: ./src
target: /app/src
action: sync

nginx:
build:
Expand Down
6 changes: 5 additions & 1 deletion compose/docker-compose.debug.arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ services:
timeout: 10s
retries: 5
start_period: 10s

develop:
watch:
- path: ./src
target: /app/src
action: sync

nginx:
build:
Expand Down
3 changes: 2 additions & 1 deletion compose/startup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ dotnet watch run \
-v \
--project /app/src/Template.Api/Template.Api.csproj \
--urls "http://*:5000" \
--non-interactive
--non-interactive \
--disable-parallel
84 changes: 77 additions & 7 deletions src/Template.Api/Controllers/IdentityController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
using Template.Application.Identity.Commands.ChangePassword;
using Template.Application.Identity.Commands.CreateUser;
using Template.Application.Identity.Commands.DeleteUser;
using Template.Application.Identity.Commands.ExternalSignIn;
using Template.Application.Identity.Commands.ForgotPassword;
using Template.Application.Identity.Commands.ResendConfirmationEmail;
using Template.Application.Identity.Commands.ResetPassword;
using Template.Application.Identity.Commands.VerifyEmail;
using Template.Application.Identity.Queries.GetProvider;
using Template.Domain.Common.Constants;
using Template.Domain.Common.Models;
using Template.Domain.Identity.Constants.Authorization;

Expand All @@ -18,9 +21,12 @@ namespace Template.Api.Controllers;
[ApiController]
[Route("api/[controller]")]
[ApiVersion("1.0")]
public class IdentityController(ILogger<IdentityController> _logger, IMediator _mediator)
public class IdentityController(ILogger<IdentityController> logger, IMediator mediator)
: ControllerBase
{
private readonly ILogger<IdentityController> _logger = logger;
private readonly IMediator _mediator = mediator;

[AllowAnonymous]
[HttpPost("register")]
[ProducesResponseType(typeof(Result<object>), StatusCodes.Status200OK)]
Expand Down Expand Up @@ -143,7 +149,7 @@ [FromBody] ResetPasswordCommand request

[Authorize(
AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme,
Policy = Policy.Update
Policy = Policy.UpdateProfilePasswordAccess
)]
[HttpPut("password/change")]
[ProducesResponseType(typeof(Result<object>), StatusCodes.Status200OK)]
Expand Down Expand Up @@ -172,18 +178,16 @@ [FromBody] ChangePasswordCommand request

[Authorize(
AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme,
Policy = Policy.Delete
Policy = Policy.DeleteAccess
)]
[HttpDelete("delete")]
[ProducesResponseType(typeof(Result<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Result<object>), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Result<object>>> DeleteUserAsync(
[FromBody] DeleteUserCommand request
)
public async Task<ActionResult<Result<object>>> DeleteUserAsync()
{
try
{
request.Email = User.FindFirst(ClaimTypes.Email)?.Value;
var request = new DeleteUserCommand(User.FindFirst(ClaimTypes.Email)?.Value);

var result = await _mediator.Send(request);

Expand All @@ -198,4 +202,70 @@ [FromBody] DeleteUserCommand request
throw;
}
}

[AllowAnonymous]
[HttpGet(TemplateDefaults.LoginPath)]
public async Task<IActionResult> Login(string returnUrl)
{
try
{
var request = new GetProviderQuery(returnUrl, Request);

var result = await _mediator.Send(request);

if (!result.Succeeded)
return BadRequest(result);

return Challenge(result.Body.Properties, result.Body.Provider);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message, nameof(Login));
throw;
}
}

[AllowAnonymous]
[HttpGet(TemplateDefaults.CallbackPath)]
public async Task<IActionResult> ExternalLoginCallback()
{
try
{
var request = new ExternalSignInCommand(HttpContext);

var result = await _mediator.Send(request);

if (!result.Succeeded)
return BadRequest(result);

return Redirect(result.Body);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message, nameof(ExternalLoginCallback));
throw;
}
}

[AllowAnonymous]
[HttpGet(TemplateDefaults.LogoutPath)]
public async Task<IActionResult> Logout(string logoutId)
{
try
{
var request = new ExternalSignOutCommand(logoutId);

var result = await _mediator.Send(request);

if (!result.Succeeded)
return BadRequest(result);

return Redirect(result.Body);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message, nameof(Logout));
throw;
}
}
}
4 changes: 2 additions & 2 deletions src/Template.Api/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Template.Api.Configurations;
using Template.Api.Extensions;
using Template.Api.Infrastructure;

namespace Template.Api;
Expand All @@ -10,7 +10,7 @@ public static IServiceCollection AddApi(this IServiceCollection services)
services.AddExceptionHandler<GlobalExceptionHandler>();
services.AddProblemDetails();

services.ConfigureSwagger().ConfigureApiVersioning();
services.AddSwaggerConfiguration().AddApiVersioningConfiguration();

return services;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;

namespace Template.Api.Configurations;
namespace Template.Api.Extensions;

public static class ApiVersioningConfiguration
public static class ApiVersioningExtension
{
public static IServiceCollection ConfigureApiVersioning(this IServiceCollection services)
public static IServiceCollection AddApiVersioningConfiguration(this IServiceCollection services)
{
services.AddApiVersioning(options =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Microsoft.AspNetCore.HttpOverrides;

namespace Template.Api.Configurations;
namespace Template.Api.Extensions;

public static class ForwardedHeadersConfiguration
public static class ForwardedHeadersExtension
{
public static IApplicationBuilder UseForwardedHeadersConfiguration(this IApplicationBuilder app)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;

namespace Template.Api.Configurations;
namespace Template.Api.Extensions;

public static class SwaggerConfiguration
public static class SwaggerExtension
{
public static IServiceCollection ConfigureSwagger(this IServiceCollection services)
public static IServiceCollection AddSwaggerConfiguration(this IServiceCollection services)
{
services.AddSwaggerGen(options =>
{
Expand Down
6 changes: 4 additions & 2 deletions src/Template.Api/Infrastructure/GlobalExceptionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

namespace Template.Api.Infrastructure;

public class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> _logger) : IExceptionHandler
public class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger = logger;

public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
Expand All @@ -16,7 +18,7 @@ CancellationToken cancellationToken

var error = new Error
{
Code = ErrorCode.INTERNAL_SERVER_ERROR,
Code = ErrorCode.InternalServerError,
Description = ErrorMessage.INTERNAL_SERVER_ERROR
};

Expand Down
16 changes: 10 additions & 6 deletions src/Template.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using Template.Api;
using Template.Api.Configurations;
using Template.Api.Extensions;
using Template.Application;
using Template.Infrastructure;
using Template.Infrastructure.IdentityServer.Configurations;
using Template.Infrastructure.IdentityServer.Extensions;

var builder = WebApplication.CreateBuilder(args);

builder
.Configuration.SetBasePath(builder.Environment.ContentRootPath)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: false)
// * OPTIONAL set to true due to latter introduction to ConfigMap
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();

builder.Services.AddApi().AddInfrastructure(builder.Configuration).AddApplication();
Expand All @@ -17,19 +18,22 @@

if (app.Environment.IsDevelopment())
{
await IdentityServerMigrationConfiguration.ApplyMigrationsAsync(app);
await IdentityServerMigrationExtension.ApplyMigrationsAsync(app);
app.UseDeveloperExceptionPage();
app.UseSwaggerConfiguration();
}

app.UseCors(options =>
{
options.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod();
});

app.UseForwardedHeadersConfiguration();

app.UseExceptionHandler();

app.UseIdentityServer();

app.UseAuthentication();

app.UseAuthorization();

app.MapControllers();
Expand Down
8 changes: 4 additions & 4 deletions src/Template.Api/Template.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

<ItemGroup>
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
Expand Down
12 changes: 6 additions & 6 deletions src/Template.Api/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
"Secret": "Un1t4hyniisKJvGAJ6l30eW3D2vKt0"
},
"GoogleWeb": {
"InternalSecret": "",
"ExternalClientId": "",
"ExternalClientSecret": "",
"RedirectUri": "",
"PostLogoutRedirectUri": "",
"AllowedCorsOrigin": ""
"InternalSecret": "44CfU7C7fB0k3oeATDkbzuJqswh3zk",
"ExternalClientId": "############### GET YOUR CLIENT ID FROM THE GCP CONSOLE ###############",
"ExternalClientSecret": "############### GET YOUR CLIENT SECRET FROM THE GCP CONSOLE ###############",
"RedirectUri": "http://localhost:3000/signin-redirect",
"PostLogoutRedirectUri": "http://localhost:3000/signout-redirect",
"AllowedCorsOrigin": "http://localhost:3000"
}
},
"IssuerUri": "http://localhost",
Expand Down
Loading
Loading