Added new web api project for testing; AcceptTokenFromQuery feature in NDB.Security.Authentication.Identity
parent
32d8dc0c4e
commit
25ea2cc4f1
|
@ -8,5 +8,6 @@ namespace NDB.Security.Authentication.Identity.Abstractions
|
|||
Func<HttpRequest, bool> AuthenticateAsGuest { get; }
|
||||
int GuestUserId { get; }
|
||||
string GuestUserName { get; }
|
||||
bool AcceptTokenFromQuery { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace NDB.Security.Authentication.Identity
|
|||
{
|
||||
public static IServiceCollection AddIdentityAuthentication(this IServiceCollection services, string identityServerBaseAddress)
|
||||
{
|
||||
services.AddIdentityAuthentication(identityServerBaseAddress, new Services.AuthenticationOptions());
|
||||
services.AddIdentityAuthentication(identityServerBaseAddress, new Models.AuthenticationOptions());
|
||||
return services;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace NDB.Security.Authentication.Identity.Constants
|
||||
{
|
||||
internal struct QueryParams
|
||||
{
|
||||
public const string
|
||||
Token = "token";
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NDB.Security.Authentication.Identity.Abstractions;
|
||||
using c = NDB.Security.Authentication.Identity.Constants;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
|
@ -27,28 +28,17 @@ namespace NDB.Security.Authentication.Identity
|
|||
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
if (!Request.Headers.ContainsKey("Authorization"))
|
||||
var token = GetAuthorizationToken();
|
||||
if (token != null)
|
||||
{
|
||||
var authenticateAsGuest = _authenticationOptions.AuthenticateAsGuest?.Invoke(Request) ?? false;
|
||||
if (authenticateAsGuest)
|
||||
{
|
||||
var guestTicket = GetGuestAuthenticationTicket(_authenticationOptions.GuestUserId, _authenticationOptions.GuestUserName);
|
||||
return AuthenticateResult.Success(guestTicket);
|
||||
}
|
||||
|
||||
return AuthenticateResult.Fail("Missing Authorization Header");
|
||||
}
|
||||
|
||||
TokenCore tokenCore;
|
||||
try
|
||||
{
|
||||
var authorizationHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
|
||||
var token = authorizationHeader.Parameter;
|
||||
tokenCore = await _identityService.Authorize(token);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return AuthenticateResult.Fail("Invalid authorization header");
|
||||
return AuthenticateResult.Fail("Invalid authorization");
|
||||
}
|
||||
|
||||
if (tokenCore == null)
|
||||
|
@ -58,6 +48,36 @@ namespace NDB.Security.Authentication.Identity
|
|||
return AuthenticateResult.Success(ticket);
|
||||
}
|
||||
|
||||
var authenticateAsGuest = _authenticationOptions.AuthenticateAsGuest?.Invoke(Request) ?? false;
|
||||
if (authenticateAsGuest)
|
||||
{
|
||||
var guestTicket = GetGuestAuthenticationTicket(_authenticationOptions.GuestUserId, _authenticationOptions.GuestUserName);
|
||||
return AuthenticateResult.Success(guestTicket);
|
||||
}
|
||||
|
||||
return AuthenticateResult.Fail("Missing authorization header");
|
||||
}
|
||||
|
||||
private string GetAuthorizationToken()
|
||||
{
|
||||
if (Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
var authorizationHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
|
||||
var token = authorizationHeader.Parameter;
|
||||
return token;
|
||||
}
|
||||
|
||||
if (_authenticationOptions.AcceptTokenFromQuery
|
||||
&& Request.Query.Count > 0
|
||||
&& Request.Query.ContainsKey(c.QueryParams.Token))
|
||||
{
|
||||
var token = Request.Query[c.QueryParams.Token];
|
||||
return token.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private AuthenticationTicket GetGuestAuthenticationTicket(int guestId, string guestName)
|
||||
{
|
||||
var claims = new[] {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using NDB.Security.Authentication.Identity.Abstractions;
|
||||
using System;
|
||||
|
||||
namespace NDB.Security.Authentication.Identity.Services
|
||||
namespace NDB.Security.Authentication.Identity.Models
|
||||
{
|
||||
public class AuthenticationOptions : IAuthenticationOptions
|
||||
{
|
||||
|
@ -11,5 +11,6 @@ namespace NDB.Security.Authentication.Identity.Services
|
|||
public int GuestUserId { get; set; }
|
||||
|
||||
public string GuestUserName { get; set; }
|
||||
public bool AcceptTokenFromQuery { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
||||
namespace NDB.Test.Api.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class DebugController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<DebugController> _logger;
|
||||
|
||||
public DebugController(ILogger<DebugController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("ping")]
|
||||
public IActionResult Ping()
|
||||
{
|
||||
return Ok($"Ping success. System datetime: {DateTime.Now}");
|
||||
}
|
||||
|
||||
[HttpGet("ping-auth")]
|
||||
public IActionResult PingAuth()
|
||||
{
|
||||
return Ok($"Secured ping success. System datetime: {DateTime.Now}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NDB.Security.Authentication.Identity;
|
||||
using NDB.Security.Authentication.Identity.Models;
|
||||
using System.Linq;
|
||||
|
||||
namespace NDB.Test.Api.Extensions
|
||||
{
|
||||
public static class AuthenticationExtensions
|
||||
{
|
||||
private record GuestRoute(string Route, int PathElements);
|
||||
private static readonly GuestRoute[] _resourcesRoutes = new GuestRoute[]
|
||||
{
|
||||
new GuestRoute("/resources", 1),
|
||||
new GuestRoute("/images", 1),
|
||||
new GuestRoute("/spot", 2)
|
||||
};
|
||||
|
||||
public static IServiceCollection AddIdentityAuthentication(this IServiceCollection services, string identityServerBaseAddress)
|
||||
{
|
||||
var authenticationOptions = new AuthenticationOptions()
|
||||
{
|
||||
AuthenticateAsGuest = (HttpRequest request) =>
|
||||
{
|
||||
var authenticateAsGuest = AuthenticateAsGuest(request);
|
||||
return authenticateAsGuest;
|
||||
},
|
||||
GuestUserName = "Guest",
|
||||
GuestUserId = -111,
|
||||
AcceptTokenFromQuery = true
|
||||
};
|
||||
|
||||
services.AddIdentityAuthentication(identityServerBaseAddress, authenticationOptions);
|
||||
return services;
|
||||
}
|
||||
|
||||
private static bool AuthenticateAsGuest(HttpRequest request)
|
||||
{
|
||||
if (!request.Path.HasValue)
|
||||
return false;
|
||||
|
||||
var guestRoute = _resourcesRoutes.FirstOrDefault(z => request.Path.Value.StartsWith(z.Route));
|
||||
if (guestRoute == null)
|
||||
return false;
|
||||
|
||||
var resourceRequestedById = request.Query.Count > 0 && request.Query.ContainsKey("id");
|
||||
if (resourceRequestedById)
|
||||
return false;
|
||||
|
||||
var resourceRequestedByCode = request.Query.Count > 0 && request.Query.ContainsKey("code");
|
||||
if (resourceRequestedByCode)
|
||||
return true;
|
||||
|
||||
var resourceRequestedByName = request.Path.Value.Replace(guestRoute.Route, string.Empty).Substring(1).Split("/").Length == guestRoute.PathElements;
|
||||
if (resourceRequestedByName)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NDB.Extensions.Swagger\NDB.Extensions.Swagger.csproj" />
|
||||
<ProjectReference Include="..\NDB.Security.Authentication.Identity\NDB.Security.Authentication.Identity.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,26 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NDB.Test.Api
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"NDB.Test.Api": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using NDB.Extensions.Swagger;
|
||||
using NDB.Extensions.Swagger.Constants;
|
||||
using NDB.Test.Api.Extensions;
|
||||
|
||||
namespace NDB.Test.Api
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add basic authentication
|
||||
services.AddIdentityAuthentication(Configuration.GetSection("IdentityServer")["BaseAddress"]);
|
||||
|
||||
services.AddControllers();
|
||||
services.AddSwagger("NDB.Test.Api", AuthorizationType.InhouseIdentity);
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "NDB.Test.Api v1"));
|
||||
}
|
||||
|
||||
app.ConfigureSwagger("NDB.Test.Api v1");
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"IdentityServer": {
|
||||
//"BaseAddress": "http://localhost:5063/"
|
||||
"BaseAddress": "https://toodle.ddns.net/identity-server-api/"
|
||||
}
|
||||
}
|
16
NDB.sln
16
NDB.sln
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29324.140
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NDB.Hosting.WindowsService", "NDB.Hosting.WindowsService\NDB.Hosting.WindowsService.csproj", "{F4AB0B71-6B14-402B-8B05-128AFB3E06D9}"
|
||||
EndProject
|
||||
|
@ -54,7 +54,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NDB.Security.Authentication
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "caching", "caching", "{A206A484-3ACF-4032-8B36-AC93A72B0B88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDB.Extensions.Caching", "NDB.Extensions.Caching\NDB.Extensions.Caching.csproj", "{3E045EE6-A290-467C-B503-3A6CB0065C97}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NDB.Extensions.Caching", "NDB.Extensions.Caching\NDB.Extensions.Caching.csproj", "{3E045EE6-A290-467C-B503-3A6CB0065C97}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCEE458E-02A8-42FD-8F5F-A35481A23303}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDB.Test.Api", "NDB.Test.Api\NDB.Test.Api.csproj", "{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -102,6 +106,10 @@ Global
|
|||
{3E045EE6-A290-467C-B503-3A6CB0065C97}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3E045EE6-A290-467C-B503-3A6CB0065C97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3E045EE6-A290-467C-B503-3A6CB0065C97}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -127,6 +135,8 @@ Global
|
|||
{5C0637C8-6BA4-4EAE-97CA-BB8D98B2991A} = {B8132F39-6677-4D70-84CA-9747DC9086B3}
|
||||
{A206A484-3ACF-4032-8B36-AC93A72B0B88} = {B50B55F0-9E6E-4061-9100-E2329A44E76B}
|
||||
{3E045EE6-A290-467C-B503-3A6CB0065C97} = {A206A484-3ACF-4032-8B36-AC93A72B0B88}
|
||||
{CCEE458E-02A8-42FD-8F5F-A35481A23303} = {E0202271-4E92-4DB8-900D-B5FD745B9278}
|
||||
{F717BE3D-F5F4-4D99-B96D-D0A23E8BED01} = {CCEE458E-02A8-42FD-8F5F-A35481A23303}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {87541BAB-3FAC-4ADB-A7FB-8228DA87843D}
|
||||
|
|
Loading…
Reference in New Issue