Skip to content

Commit 8fe464c

Browse files
authored
Polish codes in UI project. (#143)
Polish codes in UI project.
1 parent 1fb2a7b commit 8fe464c

30 files changed

+618
-645
lines changed

src/Serilog.Ui.Core/Attributes/CodeColumnAttribute.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ public class CodeColumnAttribute(CodeType codeType) : Attribute
1212
/// <summary>
1313
/// Gets the CodeType.
1414
/// </summary>
15-
public readonly CodeType CodeType = codeType;
16-
}
15+
public CodeType CodeType { get; } = codeType;
16+
}
Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
using System.Threading.Tasks;
22

3-
namespace Serilog.Ui.Core.Interfaces
3+
namespace Serilog.Ui.Core.Interfaces;
4+
5+
/// <summary>
6+
/// Authorization filter, used to authorize access to Serilog Ui pages.
7+
/// Runs synchronous.
8+
/// </summary>
9+
public interface IUiAuthorizationFilter
410
{
511
/// <summary>
6-
/// Authorization filter, used to authorize access to Serilog Ui pages.
7-
/// Runs synchronous.
12+
/// Authorizes a request sync.
813
/// </summary>
9-
public interface IUiAuthorizationFilter
10-
{
11-
/// <summary>
12-
/// Authorizes a request sync.
13-
/// </summary>
14-
bool Authorize();
15-
}
14+
bool Authorize();
15+
}
1616

17+
/// <summary>
18+
/// Authorization filter, used to authorize access to Serilog Ui pages.
19+
/// Runs asynchronous.
20+
/// </summary>
21+
public interface IUiAsyncAuthorizationFilter
22+
{
1723
/// <summary>
18-
/// Authorization filter, used to authorize access to Serilog Ui pages.
19-
/// Runs asynchronous.
24+
/// Authorizes a request async.
2025
/// </summary>
21-
public interface IUiAsyncAuthorizationFilter
22-
{
23-
/// <summary>
24-
/// Authorizes a request async.
25-
/// </summary>
26-
Task<bool> AuthorizeAsync();
27-
}
26+
Task<bool> AuthorizeAsync();
2827
}
Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,41 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Net;
5-
using System.Threading.Tasks;
6-
using Microsoft.AspNetCore.Http;
7-
using Serilog.Ui.Core.Interfaces;
1+
using Serilog.Ui.Core.Interfaces;
82

9-
namespace Serilog.Ui.Web.Authorization
3+
namespace Serilog.Ui.Web.Authorization;
4+
5+
internal sealed class AuthorizationFilterService(
6+
IHttpContextAccessor httpContextAccessor,
7+
IEnumerable<IUiAuthorizationFilter> syncFilters,
8+
IEnumerable<IUiAsyncAuthorizationFilter> asyncFilters
9+
) : IAuthorizationFilterService
1010
{
11-
internal sealed class AuthorizationFilterService(
12-
IHttpContextAccessor httpContextAccessor,
13-
IEnumerable<IUiAuthorizationFilter> syncFilters,
14-
IEnumerable<IUiAsyncAuthorizationFilter> asyncFilters) : IAuthorizationFilterService
11+
private readonly HttpContext _httpContext = Guard.Against.Null(httpContextAccessor.HttpContext);
12+
13+
public async Task CheckAccessAsync(Func<Task> onSuccess, Func<Task>? onFailure = null)
1514
{
16-
public async Task CheckAccessAsync(
17-
Func<Task> onSuccess,
18-
Func<Task>? onFailure = null)
15+
bool accessCheck = await CanAccessAsync();
16+
if (accessCheck)
1917
{
20-
var httpContext = httpContextAccessor.HttpContext;
21-
if (httpContext is null) return;
22-
23-
var accessCheck = await CanAccessAsync();
24-
25-
if (accessCheck)
26-
{
27-
await onSuccess();
28-
return;
29-
}
30-
31-
httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
32-
if (onFailure != null)
33-
{
34-
await onFailure.Invoke();
35-
}
18+
await onSuccess();
19+
return;
3620
}
3721

38-
private async Task<bool> CanAccessAsync()
22+
_httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
23+
if (onFailure != null)
3924
{
40-
var syncFilterResult = syncFilters.Any(filter => !filter.Authorize());
25+
await onFailure.Invoke();
26+
}
27+
}
4128

42-
var asyncFilter = await Task.WhenAll(asyncFilters.Select(filter => filter.AuthorizeAsync()));
43-
var asyncFilterResult = Array.Exists(asyncFilter, filter => !filter);
29+
private async Task<bool> CanAccessAsync()
30+
{
31+
// Evaluate all synchronous filters and check if any of them deny access.
32+
bool syncAuthorizeResult = syncFilters.Any(filter => !filter.Authorize());
4433

45-
return !syncFilterResult && !asyncFilterResult;
46-
}
34+
// Evaluate all asynchronous filters and check if any of them deny access.
35+
bool[] asyncFilter = await Task.WhenAll(asyncFilters.Select(filter => filter.AuthorizeAsync()));
36+
bool asyncAuthorizeResult = Array.Exists(asyncFilter, filter => !filter);
37+
38+
// Return true if all filters grant access, otherwise return false.
39+
return !syncAuthorizeResult && !asyncAuthorizeResult;
4740
}
4841
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Net.Http.Headers;
2+
using System.Text;
3+
using Microsoft.Extensions.Configuration;
4+
5+
namespace Serilog.Ui.Web.Authorization.Filters;
6+
7+
internal class BasicAuthServiceByConfiguration(IConfiguration configuration) : IBasicAuthenticationService
8+
{
9+
private readonly string? _userName = configuration["SerilogUi:UserName"];
10+
private readonly string? _password = configuration["SerilogUi:Password"];
11+
12+
public Task<bool> CanAccessAsync(AuthenticationHeaderValue basicHeader)
13+
{
14+
var header = basicHeader.Parameter;
15+
16+
return Task.FromResult(EvaluateAuthResult(header));
17+
}
18+
19+
private bool EvaluateAuthResult(string? header)
20+
{
21+
var (userName, password) = ExtractAuthenticationTokens(header);
22+
return userName == _userName && password == _password;
23+
}
24+
25+
private static (string userName, string password) ExtractAuthenticationTokens(string? authValues)
26+
{
27+
var parameter = Encoding.UTF8.GetString(Convert.FromBase64String(authValues ?? string.Empty));
28+
var parts = parameter.Split(':');
29+
return (parts[0], parts[1]);
30+
}
31+
}
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Net.Http.Headers;
3-
using System.Threading.Tasks;
4-
using Microsoft.AspNetCore.Http;
1+
using System.Net.Http.Headers;
52
using Serilog.Ui.Core.Interfaces;
63

74
namespace Serilog.Ui.Web.Authorization.Filters;
@@ -12,15 +9,12 @@ internal class BasicAuthenticationFilter(
129
: IUiAsyncAuthorizationFilter
1310
{
1411
private const string AuthenticationScheme = "Basic";
12+
private readonly HttpContext _httpContext = Guard.Against.Null(httpContextAccessor.HttpContext);
1513

1614
public async Task<bool> AuthorizeAsync()
1715
{
18-
var httpContext = httpContextAccessor.HttpContext;
19-
if (httpContext is null) return false;
20-
21-
var header = httpContext.Request.Headers.Authorization;
22-
23-
var authValues = AuthenticationHeaderValue.Parse(header!);
16+
StringValues header = _httpContext.Request.Headers.Authorization;
17+
AuthenticationHeaderValue authValues = AuthenticationHeaderValue.Parse(header!);
2418

2519
return
2620
// not basic, thus no evaluation should happen
@@ -31,6 +25,6 @@ public async Task<bool> AuthorizeAsync()
3125

3226
private static bool IsBasicAuthentication(AuthenticationHeaderValue authValues)
3327
{
34-
return AuthenticationScheme.Equals(authValues.Scheme, StringComparison.InvariantCultureIgnoreCase);
28+
return AuthenticationScheme.Equals(authValues.Scheme, StringComparison.OrdinalIgnoreCase);
3529
}
3630
}
Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,16 @@
1-
using System;
2-
using System.Net.Http.Headers;
3-
using System.Text;
4-
using System.Threading.Tasks;
5-
using Microsoft.Extensions.Configuration;
1+
using System.Net.Http.Headers;
62

73
namespace Serilog.Ui.Web.Authorization.Filters;
84

5+
/// <summary>
6+
/// Provides basic authentication services.
7+
/// </summary>
98
public interface IBasicAuthenticationService
109
{
10+
/// <summary>
11+
/// Determines whether access is granted based on the provided basic authentication header.
12+
/// </summary>
13+
/// <param name="basicHeader">The basic authentication header containing the credentials.</param>
14+
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean indicating whether access is granted.</returns>
1115
Task<bool> CanAccessAsync(AuthenticationHeaderValue basicHeader);
12-
}
13-
14-
internal class BasicAuthServiceByConfiguration(IConfiguration configuration) : IBasicAuthenticationService
15-
{
16-
private string? UserName { get; } = configuration["SerilogUi:UserName"];
17-
18-
private string? Password { get; } = configuration["SerilogUi:Password"];
19-
20-
public Task<bool> CanAccessAsync(AuthenticationHeaderValue basicHeader)
21-
{
22-
var header = basicHeader.Parameter;
23-
24-
return Task.FromResult(EvaluateAuthResult(header));
25-
}
26-
27-
private bool EvaluateAuthResult(string? header)
28-
{
29-
var tokens = ExtractAuthenticationTokens(header);
30-
var matchCredentials = CredentialsMatch(tokens);
31-
32-
return matchCredentials;
33-
}
34-
35-
private static (string, string) ExtractAuthenticationTokens(string? authValues)
36-
{
37-
var parameter = Encoding.UTF8.GetString(Convert.FromBase64String(authValues ?? string.Empty));
38-
var parts = parameter.Split(':');
39-
return (parts[0], parts[1]);
40-
}
41-
42-
private bool CredentialsMatch((string Username, string Password) tokens)
43-
{
44-
return tokens.Username == UserName && tokens.Password == Password;
45-
}
4616
}
Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1-
using Microsoft.AspNetCore.Http;
2-
using Serilog.Ui.Core.Interfaces;
1+
using Serilog.Ui.Core.Interfaces;
32
using Serilog.Ui.Web.Extensions;
43

5-
namespace Serilog.Ui.Web.Authorization.Filters
6-
{
7-
internal class LocalRequestsOnlyAuthorizationFilter(IHttpContextAccessor httpContextAccessor) : IUiAuthorizationFilter
8-
{
9-
public bool Authorize()
10-
{
11-
var httpContext = httpContextAccessor.HttpContext;
4+
namespace Serilog.Ui.Web.Authorization.Filters;
125

13-
return httpContext is not null && httpContext.Request.IsLocal();
14-
}
15-
}
6+
internal class LocalRequestsOnlyAuthorizationFilter(IHttpContextAccessor httpContextAccessor) : IUiAuthorizationFilter
7+
{
8+
public bool Authorize() =>
9+
httpContextAccessor.HttpContext is not null &&
10+
httpContextAccessor.HttpContext.Request.IsLocal();
1611
}
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
using System.Threading.Tasks;
2-
using Microsoft.AspNetCore.Authorization;
3-
using Microsoft.AspNetCore.Http;
1+
using Microsoft.AspNetCore.Authorization;
42
using Serilog.Ui.Core.Interfaces;
53

64
namespace Serilog.Ui.Web.Authorization.Filters;
75

86
internal class PolicyAuthorizationFilter(
97
IHttpContextAccessor httpContextAccessor,
108
IAuthorizationService authorizationService,
11-
string policy)
12-
: IUiAsyncAuthorizationFilter
9+
string policy
10+
) : IUiAsyncAuthorizationFilter
1311
{
12+
private readonly HttpContext _httpContext = Guard.Against.Null(httpContextAccessor.HttpContext);
13+
1414
public async Task<bool> AuthorizeAsync()
1515
{
16-
var httpContext = httpContextAccessor.HttpContext;
17-
if (httpContext is null) return false;
18-
19-
var result = await authorizationService.AuthorizeAsync(httpContext.User, policy);
16+
AuthorizationResult result = await authorizationService.AuthorizeAsync(_httpContext.User, policy);
2017
return result.Succeeded;
2118
}
2219
}
Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
using System;
2-
using System.Threading.Tasks;
1+
namespace Serilog.Ui.Web.Authorization;
32

4-
namespace Serilog.Ui.Web.Authorization
3+
/// <summary>
4+
/// Provides services for authorization filtering.
5+
/// </summary>
6+
internal interface IAuthorizationFilterService
57
{
6-
internal interface IAuthorizationFilterService
7-
{
8-
Task CheckAccessAsync(Func<Task> onSuccess, Func<Task>? onFailure = null);
9-
}
8+
/// <summary>
9+
/// Checks access and executes the appropriate callback based on the result.
10+
/// </summary>
11+
/// <param name="onSuccess">The callback to execute if access is granted.</param>
12+
/// <param name="onFailure">The optional callback to execute if access is denied.</param>
13+
/// <returns>A task that represents the asynchronous operation.</returns>
14+
Task CheckAccessAsync(Func<Task> onSuccess, Func<Task>? onFailure = null);
1015
}
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
using System.IO;
2-
using Serilog.Ui.Web.Models;
1+
using Serilog.Ui.Web.Models;
32

4-
namespace Serilog.Ui.Web.Endpoints
3+
namespace Serilog.Ui.Web.Endpoints;
4+
5+
internal class AppStreamLoader : IAppStreamLoader
56
{
6-
internal class AppStreamLoader : IAppStreamLoader
7-
{
8-
private const string AppManifest = "Serilog.Ui.Web.wwwroot.dist.index.html";
7+
private const string AppManifest = "Serilog.Ui.Web.wwwroot.dist.index.html";
98

10-
public Stream? GetIndex() =>
11-
typeof(AuthorizationOptions)
12-
.Assembly
13-
.GetManifestResourceStream(AppManifest);
14-
}
9+
public Stream? GetIndex() =>
10+
typeof(AuthorizationOptions)
11+
.Assembly
12+
.GetManifestResourceStream(AppManifest);
1513
}
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
using System.IO;
1+
namespace Serilog.Ui.Web.Endpoints;
22

3-
namespace Serilog.Ui.Web.Endpoints
3+
/// <summary>
4+
/// Provides methods to load application streams.
5+
/// </summary>
6+
internal interface IAppStreamLoader
47
{
5-
internal interface IAppStreamLoader
6-
{
7-
Stream? GetIndex();
8-
}
8+
/// <summary>
9+
/// Gets the index stream.
10+
/// </summary>
11+
/// <returns>The index stream, or null if the stream is not available.</returns>
12+
Stream? GetIndex();
913
}

0 commit comments

Comments
 (0)