Add API key authorisation.
This commit is contained in:
parent
f8e8774d8c
commit
c041c42dcf
8 changed files with 124 additions and 5 deletions
|
@ -18,10 +18,16 @@ steps:
|
||||||
environment:
|
environment:
|
||||||
ConnectionString:
|
ConnectionString:
|
||||||
from_secret: ConnectionString
|
from_secret: ConnectionString
|
||||||
|
AuthEndpoint:
|
||||||
|
from_secret: AuthEndpoint
|
||||||
|
AuthApiKey:
|
||||||
|
from_secret: AuthApiKey
|
||||||
commands:
|
commands:
|
||||||
- chmod +x ./build.sh
|
- chmod +x ./build.sh
|
||||||
- ./build.sh
|
- ./build.sh
|
||||||
- sed -i "s/<DatabaseConnectionString>/$ConnectionString/g" output/appsettings.json
|
- sed -i "s/<DatabaseConnectionString>/$ConnectionString/g" output/appsettings.json
|
||||||
|
- sed -i "s/<AuthEndpoint>/$AuthEndpoint/g" output/appsettings.json
|
||||||
|
- sed -i "s/<AuthApiKey>/$AuthApiKey/g" output/appsettings.json
|
||||||
- cp api.blog.service output/
|
- cp api.blog.service output/
|
||||||
- cp -r ./output/* /output
|
- cp -r ./output/* /output
|
||||||
- name: restart service
|
- name: restart service
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Robware.Api.Blog.Authentication {
|
||||||
|
public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions> {
|
||||||
|
private const string ApiKeyHeaderName = "X-Api-Key";
|
||||||
|
private readonly ApiKeyValidator _apiKeyValidator;
|
||||||
|
|
||||||
|
public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
ISystemClock clock,
|
||||||
|
ApiKeyValidator apiKeyValidator)
|
||||||
|
: base(options, logger, encoder, clock) {
|
||||||
|
_apiKeyValidator = apiKeyValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
|
||||||
|
if (!Request.Headers.TryGetValue(ApiKeyHeaderName, out var apiKeyHeaderValues)) {
|
||||||
|
return AuthenticateResult.NoResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiKey = apiKeyHeaderValues.FirstOrDefault();
|
||||||
|
|
||||||
|
if (apiKeyHeaderValues.Count == 0 || string.IsNullOrWhiteSpace(apiKey)) {
|
||||||
|
return AuthenticateResult.NoResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await _apiKeyValidator.Validate(apiKey)) {
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim(ApiKeyHeaderName, apiKey)
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(claims, Options.AuthenticationType);
|
||||||
|
var principal = new ClaimsPrincipal(new[] { identity });
|
||||||
|
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||||
|
|
||||||
|
return AuthenticateResult.Success(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthenticateResult.Fail("Invalid API Key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task HandleChallengeAsync(AuthenticationProperties properties) {
|
||||||
|
Response.StatusCode = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties) {
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
|
namespace Robware.Api.Blog.Authentication {
|
||||||
|
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions {
|
||||||
|
public const string DefaultScheme = "API Key";
|
||||||
|
public string Scheme => DefaultScheme;
|
||||||
|
public string AuthenticationType = DefaultScheme;
|
||||||
|
}
|
||||||
|
}
|
18
src/Robware.Api.Blog/Authentication/ApiKeyValidator.cs
Normal file
18
src/Robware.Api.Blog/Authentication/ApiKeyValidator.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Robware.Api.Blog.Authentication
|
||||||
|
{
|
||||||
|
public class ApiKeyValidator {
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public ApiKeyValidator(HttpClient httpClient) {
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Validate(string apiKey) {
|
||||||
|
var response = await _httpClient.GetAsync("api/validate?key=" + apiKey);
|
||||||
|
return response.IsSuccessStatusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Robware.Api.Blog.Authentication {
|
||||||
|
public static class AuthenticationBuilderExtensions {
|
||||||
|
public static AuthenticationBuilder AddApiKeySupport(this AuthenticationBuilder authenticationBuilder, Action<ApiKeyAuthenticationOptions> options) {
|
||||||
|
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(ApiKeyAuthenticationOptions.DefaultScheme, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.10.4" />
|
<PackageReference Include="MongoDB.Driver" Version="2.10.4" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -4,8 +4,10 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
using Robware.Api.Blog.Authentication;
|
||||||
using Robware.Blog;
|
using Robware.Blog;
|
||||||
using Robware.Data;
|
using Robware.Data;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Robware.Api.Blog {
|
namespace Robware.Api.Blog {
|
||||||
public class Startup {
|
public class Startup {
|
||||||
|
@ -22,6 +24,17 @@ namespace Robware.Api.Blog {
|
||||||
services
|
services
|
||||||
.AddSingleton<IMongoDatabase>(SetupMongoDatabase())
|
.AddSingleton<IMongoDatabase>(SetupMongoDatabase())
|
||||||
.AddSingleton<IBlogRepository, BlogRepository>();
|
.AddSingleton<IBlogRepository, BlogRepository>();
|
||||||
|
|
||||||
|
services.AddHttpClient<ApiKeyValidator>(client => {
|
||||||
|
client.BaseAddress = new Uri(Configuration["authEndpoint"]);
|
||||||
|
client.DefaultRequestHeaders.Add("x-api-key", new[] {Configuration["authApiKey"]});
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(options => {
|
||||||
|
options.DefaultAuthenticateScheme = ApiKeyAuthenticationOptions.DefaultScheme;
|
||||||
|
options.DefaultChallengeScheme = ApiKeyAuthenticationOptions.DefaultScheme;
|
||||||
|
})
|
||||||
|
.AddApiKeySupport(options => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMongoDatabase SetupMongoDatabase() {
|
private IMongoDatabase SetupMongoDatabase() {
|
||||||
|
@ -39,10 +52,12 @@ namespace Robware.Api.Blog {
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints => {
|
app.UseEndpoints(endpoints => {
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers().RequireAuthorization();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,7 @@
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"database": "<DatabaseConnectionString>"
|
"database": "<DatabaseConnectionString>"
|
||||||
}
|
},
|
||||||
|
"authEndpoint": "<AuthEndpoint>",
|
||||||
|
"authApiKey": "<AuthApiKey>"
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue