Implement support for external authentication provider with Bearer tokens.
This commit is contained in:
parent
47d7706cd2
commit
e193d5394d
10 changed files with 157 additions and 38 deletions
15
Readme.md
15
Readme.md
|
@ -1,6 +1,6 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
![Under Development](https://img.shields.io/badge/status-Under%20Development-orange) ![Build Status](https://circleci.com/gh/dnutiu/retroactiune.svg?style=svg)
|
![Build Status](https://circleci.com/gh/dnutiu/retroactiune.svg?style=svg)
|
||||||
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/dnutiu/retroactiune) ![GitHub repo size](https://img.shields.io/github/repo-size/dnutiu/retroactiune) ![GitHub top language](https://img.shields.io/github/languages/top/dnutiu/retroactiune)
|
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/dnutiu/retroactiune) ![GitHub repo size](https://img.shields.io/github/repo-size/dnutiu/retroactiune) ![GitHub top language](https://img.shields.io/github/languages/top/dnutiu/retroactiune)
|
||||||
|
|
||||||
![Swagger API](./docs/retroactiune_swagger.png)
|
![Swagger API](./docs/retroactiune_swagger.png)
|
||||||
|
@ -31,6 +31,17 @@ The application code is organized using the [Clean Architecture](https://docs.mi
|
||||||
|
|
||||||
![Example deployment architecture](./docs/app_architecture_layers.png)
|
![Example deployment architecture](./docs/app_architecture_layers.png)
|
||||||
|
|
||||||
|
## Authorization Provider
|
||||||
|
|
||||||
|
An external Authorization provider is required in order to run the API, the provider needs to support
|
||||||
|
Bearer tokens and HS256 key signing algorithm. _RS256 is currently not supported._
|
||||||
|
|
||||||
|
I recommend that you start with [Auth0](https://auth0.com/) and their free tier.
|
||||||
|
|
||||||
|
See the following resources:
|
||||||
|
- https://auth0.com/docs/get-started/set-up-apis
|
||||||
|
- https://developers.redhat.com/blog/2020/01/29/api-login-and-jwt-token-generation-using-keycloak#set_up_a_client
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
To install the dependencies run `dotnet restore`.
|
To install the dependencies run `dotnet restore`.
|
||||||
|
@ -49,3 +60,5 @@ _Note: [Docker](https://www.docker.com/) and [Docker-Compose](https://docs.docke
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
dotnet test
|
dotnet test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The projects has ~96% code coverage.
|
|
@ -11,7 +11,7 @@
|
||||||
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
|
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.15" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.15" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Retroactiune.Core.Entities;
|
using Retroactiune.Core.Entities;
|
||||||
|
@ -77,9 +78,11 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="200">The feedback has been added.</response>
|
/// <response code="200">The feedback has been added.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
[HttpGet("{guid}/feedbacks")]
|
[HttpGet("{guid}/feedbacks")]
|
||||||
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> GetFeedbacks(string guid, [FromQuery] ListFeedbacksFiltersDto filters)
|
public async Task<IActionResult> GetFeedbacks(string guid, [FromQuery] ListFeedbacksFiltersDto filters)
|
||||||
{
|
{
|
||||||
var feedbacksListFilters = _mapper.Map<FeedbacksListFilters>(filters);
|
var feedbacksListFilters = _mapper.Map<FeedbacksListFilters>(filters);
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -47,9 +48,11 @@ namespace Retroactiune.Controllers
|
||||||
/// <returns>A BasicResponse indicating success.</returns>
|
/// <returns>A BasicResponse indicating success.</returns>
|
||||||
/// <response code="200">Returns an ok message.</response>
|
/// <response code="200">Returns an ok message.</response>
|
||||||
/// <response code="400">If the items is invalid</response>
|
/// <response code="400">If the items is invalid</response>
|
||||||
|
[Authorize]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> Post([Required] IEnumerable<FeedbackReceiverInDto> items)
|
public async Task<IActionResult> Post([Required] IEnumerable<FeedbackReceiverInDto> items)
|
||||||
{
|
{
|
||||||
var feedbackReceiversDto = items.ToList();
|
var feedbackReceiversDto = items.ToList();
|
||||||
|
@ -77,9 +80,11 @@ namespace Retroactiune.Controllers
|
||||||
/// <returns>A NoContent result.</returns>
|
/// <returns>A NoContent result.</returns>
|
||||||
/// <response code="204">The delete is submitted.</response>
|
/// <response code="204">The delete is submitted.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
|
[Authorize]
|
||||||
[HttpDelete("{guid}")]
|
[HttpDelete("{guid}")]
|
||||||
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<NoContentResult> Delete(
|
public async Task<NoContentResult> Delete(
|
||||||
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
||||||
string guid)
|
string guid)
|
||||||
|
@ -97,10 +102,12 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="200">The item returned successfully.</response>
|
/// <response code="200">The item returned successfully.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
/// <response code="404">The item was not found.</response>
|
/// <response code="404">The item was not found.</response>
|
||||||
|
[Authorize]
|
||||||
[HttpGet("{guid}")]
|
[HttpGet("{guid}")]
|
||||||
[ProducesResponseType(typeof(FeedbackReceiverOutDto), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FeedbackReceiverOutDto), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status404NotFound)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status404NotFound)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> Get(
|
public async Task<IActionResult> Get(
|
||||||
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
||||||
string guid)
|
string guid)
|
||||||
|
@ -128,8 +135,10 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="200">The a list is returned.</response>
|
/// <response code="200">The a list is returned.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(IEnumerable<FeedbackReceiverOutDto>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(IEnumerable<FeedbackReceiverOutDto>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> List([FromQuery] IEnumerable<string> filter,
|
public async Task<IActionResult> List([FromQuery] IEnumerable<string> filter,
|
||||||
[RangeAttribute(1, int.MaxValue, ErrorMessage = "offset is out of range, allowed ranges [1-IntMax]"),
|
[RangeAttribute(1, int.MaxValue, ErrorMessage = "offset is out of range, allowed ranges [1-IntMax]"),
|
||||||
FromQuery]
|
FromQuery]
|
||||||
|
@ -148,8 +157,10 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> DeleteMany([Required] IEnumerable<string> ids)
|
public async Task<IActionResult> DeleteMany([Required] IEnumerable<string> ids)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -39,8 +40,10 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="200">A list of tokens.</response>
|
/// <response code="200">A list of tokens.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(IEnumerable<Token>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(IEnumerable<Token>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> ListTokens([FromQuery] ListTokensFiltersDto filtersDto)
|
public async Task<IActionResult> ListTokens([FromQuery] ListTokensFiltersDto filtersDto)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -68,8 +71,10 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="200">Returns ok.</response>
|
/// <response code="200">Returns ok.</response>
|
||||||
/// <response code="400">If the items is invalid</response>
|
/// <response code="400">If the items is invalid</response>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status201Created)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status201Created)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> GenerateTokens([Required] GenerateTokensDto generateTokensDto)
|
public async Task<IActionResult> GenerateTokens([Required] GenerateTokensDto generateTokensDto)
|
||||||
{
|
{
|
||||||
var feedbackReceiverId = generateTokensDto.FeedbackReceiverId;
|
var feedbackReceiverId = generateTokensDto.FeedbackReceiverId;
|
||||||
|
@ -99,8 +104,10 @@ namespace Retroactiune.Controllers
|
||||||
/// <response code="404">The request is invalid.</response>
|
/// <response code="404">The request is invalid.</response>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(BasicResponse), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> DeleteTokens([Required] IEnumerable<string> tokenIds)
|
public async Task<IActionResult> DeleteTokens([Required] IEnumerable<string> tokenIds)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -125,9 +132,11 @@ namespace Retroactiune.Controllers
|
||||||
/// <returns>A NoContent result.</returns>
|
/// <returns>A NoContent result.</returns>
|
||||||
/// <response code="204">The delete is submitted.</response>
|
/// <response code="204">The delete is submitted.</response>
|
||||||
/// <response code="400">The request is invalid.</response>
|
/// <response code="400">The request is invalid.</response>
|
||||||
|
[Authorize]
|
||||||
[HttpDelete("{guid}")]
|
[HttpDelete("{guid}")]
|
||||||
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
[ProducesResponseType(typeof(NoContentResult), StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType( StatusCodes.Status401Unauthorized)]
|
||||||
public async Task<IActionResult> DeleteToken(
|
public async Task<IActionResult> DeleteToken(
|
||||||
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
[StringLength(24, ErrorMessage = "invalid guid, must be 24 characters", MinimumLength = 24)]
|
||||||
string guid)
|
string guid)
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<RootNamespace>Retroactiune</RootNamespace>
|
<RootNamespace>Retroactiune</RootNamespace>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>1591</NoWarn>
|
<NoWarn>1591</NoWarn>
|
||||||
|
<UserSecretsId>0efb2158-cb38-4e00-9900-48a0fa4ce3c1</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.17" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.12.3" />
|
<PackageReference Include="MongoDB.Driver" Version="2.12.3" />
|
||||||
<PackageReference Include="prometheus-net" Version="4.2.0" />
|
<PackageReference Include="prometheus-net" Version="4.2.0" />
|
||||||
<PackageReference Include="prometheus-net.AspNetCore" Version="4.2.0" />
|
<PackageReference Include="prometheus-net.AspNetCore" Version="4.2.0" />
|
||||||
<PackageReference Include="Sentry.AspNetCore" Version="3.8.1" />
|
<PackageReference Include="Sentry.AspNetCore" Version="3.8.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Retroactiune.Core\Retroactiune.Core.csproj" />
|
<ProjectReference Include="..\Retroactiune.Core\Retroactiune.Core.csproj" />
|
||||||
<ProjectReference Include="..\Retroactiune.Infrastructure\Retroactiune.Infrastructure.csproj" />
|
<ProjectReference Include="..\Retroactiune.Infrastructure\Retroactiune.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -8,6 +10,8 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using Prometheus;
|
using Prometheus;
|
||||||
using Retroactiune.Core.Interfaces;
|
using Retroactiune.Core.Interfaces;
|
||||||
|
@ -20,8 +24,6 @@ namespace Retroactiune
|
||||||
[ExcludeFromCodeCoverage]
|
[ExcludeFromCodeCoverage]
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
// TODO: External auth provider.
|
|
||||||
// TODO: Improve coverage.
|
|
||||||
// TODO: UI?
|
// TODO: UI?
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
@ -52,12 +54,51 @@ namespace Retroactiune
|
||||||
return new MongoClient(settings.Value.ConnectionString);
|
return new MongoClient(settings.Value.ConnectionString);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidIssuer = Configuration.GetSection("AuthorizationProvider:Domain").Value,
|
||||||
|
ValidAudience = Configuration.GetSection("AuthorizationProvider:Audience").Value,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(
|
||||||
|
Encoding.UTF8.GetBytes(Configuration.GetSection("AuthorizationProvider:SymmetricSecurityKey")
|
||||||
|
.Value))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// WebAPI
|
// WebAPI
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(AppContext.BaseDirectory, "Retroactiune.WebAPI.xml");
|
var filePath = Path.Combine(AppContext.BaseDirectory, "Retroactiune.WebAPI.xml");
|
||||||
c.IncludeXmlComments(filePath);
|
c.IncludeXmlComments(filePath);
|
||||||
|
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Scheme = "bearer",
|
||||||
|
Description = "Please insert JWT token into field"
|
||||||
|
});
|
||||||
|
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new string[] { }
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +124,10 @@ namespace Retroactiune
|
||||||
app.UseSentryTracing();
|
app.UseSentryTracing();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
||||||
|
|
||||||
logger.LogInformation("Running");
|
logger.LogInformation("Running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
Retroactiune.WebAPI/TestTokenAuthenticationHandler.cs
Normal file
33
Retroactiune.WebAPI/TestTokenAuthenticationHandler.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Retroactiune
|
||||||
|
{
|
||||||
|
public class TestAuthenticationOptions : AuthenticationSchemeOptions
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||||
|
public class TestTokenAuthenticationHandler : AuthenticationHandler<TestAuthenticationOptions>
|
||||||
|
{
|
||||||
|
|
||||||
|
public TestTokenAuthenticationHandler(IOptionsMonitor<TestAuthenticationOptions> options, ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder, ISystemClock clock)
|
||||||
|
: base(options, logger, encoder, clock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
var claims = new[] {new Claim("token", "allow_all")};
|
||||||
|
var identity = new ClaimsIdentity(claims, nameof(TestTokenAuthenticationHandler));
|
||||||
|
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name);
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,11 @@ namespace Retroactiune
|
||||||
return new MongoClient(settings.Value.ConnectionString);
|
return new MongoClient(settings.Value.ConnectionString);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = "Bearer";
|
||||||
|
}).AddScheme<TestAuthenticationOptions, TestTokenAuthenticationHandler> ("Bearer", o => { });
|
||||||
|
|
||||||
// WebAPI
|
// WebAPI
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +57,7 @@ namespace Retroactiune
|
||||||
{
|
{
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
{
|
{
|
||||||
|
"AuthorizationProvider": {
|
||||||
|
"Domain": "Your AuthProvider Domain",
|
||||||
|
"Audience": "Your API Url",
|
||||||
|
"SymmetricSecurityKey": "HS256 secret"
|
||||||
|
},
|
||||||
"Sentry": {
|
"Sentry": {
|
||||||
"Dsn": "",
|
"Dsn": "",
|
||||||
"MaxRequestBodySize": "Always",
|
"MaxRequestBodySize": "Always",
|
||||||
|
|
Loading…
Reference in a new issue