Skip to content

Commit 7045ad7

Browse files
committed
feat: enable nullable reference types for the library
1 parent 6028d92 commit 7045ad7

File tree

46 files changed

+255
-324
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+255
-324
lines changed

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlAttribute.cs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,35 @@ namespace WeihanLi.Web.AccessControlHelper;
1111
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
1212
public sealed class AccessControlAttribute : AuthorizationFilterAttribute
1313
{
14-
public string AccessKey { get; set; }
14+
public string? AccessKey { get; set; }
1515

1616
public override void OnAuthorization(AuthorizationFilterContext filterContext)
1717
{
18-
if (filterContext == null)
19-
throw new ArgumentNullException(nameof(filterContext));
18+
ArgumentNullException.ThrowIfNull(filterContext);
2019

2120
var isDefinedNoControl = filterContext.ActionDescriptor.IsDefined(typeof(NoAccessControlAttribute), true);
2221

23-
if (!isDefinedNoControl)
24-
{
25-
var accessStrategy = filterContext.HttpContext.RequestServices.GetService<IResourceAccessStrategy>();
26-
if (accessStrategy is null)
27-
throw new ArgumentException("IResourceAccessStrategy not initialized,please register your ResourceAccessStrategy", nameof(IResourceAccessStrategy));
22+
if (isDefinedNoControl) return;
23+
24+
var accessStrategy = filterContext.HttpContext.RequestServices.GetService<IResourceAccessStrategy>();
25+
if (accessStrategy is null)
26+
throw new InvalidOperationException("IResourceAccessStrategy not initialized,please register your ResourceAccessStrategy");
2827

29-
if (!accessStrategy.IsCanAccess(AccessKey))
30-
{
31-
//if Ajax request
32-
filterContext.Result = filterContext.HttpContext.Request.IsAjaxRequest() ?
33-
accessStrategy.DisallowedAjaxResult :
34-
accessStrategy.DisallowedCommonResult;
35-
}
28+
if (!accessStrategy.IsCanAccess(AccessKey))
29+
{
30+
//if Ajax request
31+
filterContext.Result = filterContext.HttpContext.Request.IsAjaxRequest() ?
32+
accessStrategy.DisallowedAjaxResult :
33+
accessStrategy.DisallowedCommonResult;
3634
}
3735
}
3836
}
3937

4038
internal static class AjaxRequestExtensions
4139
{
42-
public static bool IsAjaxRequest(this Microsoft.AspNetCore.Http.HttpRequest request)
40+
public static bool IsAjaxRequest(this HttpRequest request)
4341
{
44-
return request?.Headers != null && string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
42+
return "XMLHttpRequest".Equals(request.Headers.XRequestedWith, StringComparison.OrdinalIgnoreCase);
4543
}
4644

4745
public static bool IsDefined(this Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor actionDescriptor,

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlAuthorizationHandler.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,18 @@
66

77
namespace WeihanLi.Web.AccessControlHelper;
88

9-
internal sealed class AccessControlAuthorizationHandler : AuthorizationHandler<AccessControlRequirement>
9+
internal sealed class AccessControlAuthorizationHandler(
10+
IHttpContextAccessor contextAccessor,
11+
IOptions<AccessControlOptions> options)
12+
: AuthorizationHandler<AccessControlRequirement>
1013
{
11-
private readonly AccessControlOptions _options;
12-
private readonly IHttpContextAccessor _contextAccessor;
13-
14-
public AccessControlAuthorizationHandler(IHttpContextAccessor contextAccessor, IOptions<AccessControlOptions> options)
15-
{
16-
_contextAccessor = contextAccessor;
17-
_options = options.Value;
18-
}
14+
private readonly AccessControlOptions _options = options.Value;
1915

2016
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AccessControlRequirement requirement)
2117
{
22-
var httpContext = _contextAccessor.HttpContext;
23-
var accessKey = _options.AccessKeyResolver?.Invoke(httpContext);
18+
var httpContext = contextAccessor.HttpContext;
19+
ArgumentNullException.ThrowIfNull(httpContext);
20+
var accessKey = _options.AccessKeyResolver.Invoke(httpContext);
2421
var resourceAccessStrategy = Guard.NotNull(httpContext).RequestServices.GetRequiredService<IResourceAccessStrategy>();
2522
if (resourceAccessStrategy.IsCanAccess(accessKey))
2623
{

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlHelperBuilder.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@ public interface IAccessControlHelperBuilder
88
IServiceCollection Services { get; }
99
}
1010

11-
internal sealed class AccessControlHelperBuilder : IAccessControlHelperBuilder
11+
internal sealed class AccessControlHelperBuilder(IServiceCollection services) : IAccessControlHelperBuilder
1212
{
13-
public IServiceCollection Services { get; }
14-
15-
public AccessControlHelperBuilder(IServiceCollection services)
16-
{
17-
Services = services;
18-
}
13+
public IServiceCollection Services { get; } = services;
1914
}

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlHelperExtension.cs

Lines changed: 21 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ public static class ApplicationBuilderExtensions
1111
{
1212
public static IApplicationBuilder UseAccessControlHelper(this IApplicationBuilder app)
1313
{
14-
if (app == null)
15-
{
16-
throw new ArgumentNullException(nameof(app));
17-
}
14+
ArgumentNullException.ThrowIfNull(app);
1815
return app.UseMiddleware<AccessControlHelperMiddleware>();
1916
}
2017
}
@@ -28,10 +25,7 @@ public static IAccessControlHelperBuilder AddAccessControlHelper<TResourceAccess
2825
where TResourceAccessStrategy : class, IResourceAccessStrategy
2926
where TControlStrategy : class, IControlAccessStrategy
3027
{
31-
if (services == null)
32-
{
33-
throw new ArgumentNullException(nameof(services));
34-
}
28+
ArgumentNullException.ThrowIfNull(services);
3529

3630
services.TryAddSingleton<IResourceAccessStrategy, TResourceAccessStrategy>();
3731
services.TryAddSingleton<IControlAccessStrategy, TControlStrategy>();
@@ -43,53 +37,40 @@ public static IAccessControlHelperBuilder AddAccessControlHelper<TResourceAccess
4337
where TResourceAccessStrategy : class, IResourceAccessStrategy
4438
where TControlStrategy : class, IControlAccessStrategy
4539
{
46-
if (services == null)
47-
{
48-
throw new ArgumentNullException(nameof(services));
49-
}
40+
ArgumentNullException.ThrowIfNull(services);
5041

5142
services.TryAdd(new ServiceDescriptor(typeof(IResourceAccessStrategy), typeof(TResourceAccessStrategy), resourceAccessStrategyLifetime));
5243
services.TryAdd(new ServiceDescriptor(typeof(IControlAccessStrategy), typeof(TControlStrategy), controlAccessStrategyLifetime));
5344

5445
return services.AddAccessControlHelper();
5546
}
5647

57-
public static IAccessControlHelperBuilder AddAccessControlHelper<TResourceAccessStrategy, TControlStrategy>(this IServiceCollection services, Action<AccessControlOptions> configAction)
48+
public static IAccessControlHelperBuilder AddAccessControlHelper<TResourceAccessStrategy, TControlStrategy>(
49+
this IServiceCollection services, Action<AccessControlOptions> configAction)
5850
where TResourceAccessStrategy : class, IResourceAccessStrategy
5951
where TControlStrategy : class, IControlAccessStrategy
6052
{
61-
if (services == null)
62-
{
63-
throw new ArgumentNullException(nameof(services));
64-
}
65-
if (configAction != null)
66-
{
67-
services.Configure(configAction);
68-
}
53+
ArgumentNullException.ThrowIfNull(services);
54+
ArgumentNullException.ThrowIfNull(configAction);
55+
56+
services.Configure(configAction);
6957
return services.AddAccessControlHelper<TResourceAccessStrategy, TControlStrategy>();
7058
}
7159

7260
public static IAccessControlHelperBuilder AddAccessControlHelper<TResourceAccessStrategy, TControlStrategy>(this IServiceCollection services, Action<AccessControlOptions> configAction, ServiceLifetime resourceAccessStrategyLifetime, ServiceLifetime controlAccessStrategyLifetime)
7361
where TResourceAccessStrategy : class, IResourceAccessStrategy
7462
where TControlStrategy : class, IControlAccessStrategy
7563
{
76-
if (services == null)
77-
{
78-
throw new ArgumentNullException(nameof(services));
79-
}
80-
if (configAction != null)
81-
{
82-
services.Configure(configAction);
83-
}
64+
ArgumentNullException.ThrowIfNull(services);
65+
ArgumentNullException.ThrowIfNull(configAction);
66+
67+
services.Configure(configAction);
8468
return services.AddAccessControlHelper<TResourceAccessStrategy, TControlStrategy>(resourceAccessStrategyLifetime, controlAccessStrategyLifetime);
8569
}
8670

8771
public static IAccessControlHelperBuilder AddAccessControlHelper(this IServiceCollection services, bool useAsDefaultPolicy)
8872
{
89-
if (services == null)
90-
{
91-
throw new ArgumentNullException(nameof(services));
92-
}
73+
ArgumentNullException.ThrowIfNull(services);
9374

9475
if (useAsDefaultPolicy)
9576
{
@@ -127,21 +108,13 @@ public static IAccessControlHelperBuilder AddAccessControlHelper(this IServiceCo
127108

128109
public static IAccessControlHelperBuilder AddAccessControlHelper(this IServiceCollection services, Action<AccessControlOptions> configAction)
129110
{
130-
if (services == null)
131-
{
132-
throw new ArgumentNullException(nameof(services));
133-
}
134-
135-
var useAsDefaultPolicy = false;
136-
if (configAction != null)
137-
{
138-
var option = new AccessControlOptions();
139-
configAction.Invoke(option);
140-
useAsDefaultPolicy = option.UseAsDefaultPolicy;
141-
142-
services.Configure(configAction);
143-
}
144-
return services.AddAccessControlHelper(useAsDefaultPolicy);
111+
ArgumentNullException.ThrowIfNull(services);
112+
ArgumentNullException.ThrowIfNull(configAction);
113+
114+
var option = new AccessControlOptions();
115+
configAction.Invoke(option);
116+
services.Configure(configAction);
117+
return services.AddAccessControlHelper(option.UseAsDefaultPolicy);
145118
}
146119

147120
public static IAccessControlHelperBuilder AddResourceAccessStrategy<TResourceAccessStrategy>(this IAccessControlHelperBuilder builder) where TResourceAccessStrategy : IResourceAccessStrategy
Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Weihan Li. All rights reserved.
22
// Licensed under the MIT license.
33

4-
using Microsoft.Extensions.Logging;
5-
64
namespace WeihanLi.Web.AccessControlHelper;
75

86
/// <summary>
@@ -11,22 +9,20 @@ namespace WeihanLi.Web.AccessControlHelper;
119
internal sealed class AccessControlHelperMiddleware
1210
{
1311
private readonly RequestDelegate _next;
14-
private readonly ILogger _logger;
1512
private readonly AccessControlOptions _option;
1613

1714
/// <summary>
1815
/// Creates a new instance of <see cref="AccessControlHelperMiddleware"/>
1916
/// </summary>
2017
/// <param name="next">The delegate representing the next middleware in the request pipeline.</param>
2118
/// <param name="options"></param>
22-
/// <param name="logger">The Logger Factory.</param>
2319
public AccessControlHelperMiddleware(
2420
RequestDelegate next,
25-
IOptions<AccessControlOptions> options,
26-
ILogger<AccessControlHelperMiddleware> logger)
21+
IOptions<AccessControlOptions> options
22+
)
2723
{
28-
_next = next ?? throw new ArgumentNullException(nameof(next));
29-
_logger = logger;
24+
ArgumentNullException.ThrowIfNull(next);
25+
_next = next;
3026
_option = options.Value;
3127
}
3228

@@ -37,17 +33,14 @@ public AccessControlHelperMiddleware(
3733
/// <returns>A task that represents the execution of this middleware.</returns>
3834
public Task Invoke(HttpContext context)
3935
{
40-
var accessKey = _option.AccessKeyResolver?.Invoke(context);
41-
42-
var accessStrategy = context.RequestServices.GetService<IResourceAccessStrategy>();
36+
var accessKey = _option.AccessKeyResolver.Invoke(context);
37+
var accessStrategy = context.RequestServices.GetRequiredService<IResourceAccessStrategy>();
4338
if (accessStrategy.IsCanAccess(accessKey))
4439
{
4540
return _next(context);
4641
}
47-
48-
_logger.LogDebug($"Request {context.TraceIdentifier} was unauthorized, Request path:{context.Request.Path}");
49-
context.Response.StatusCode = context.User.Identity.IsAuthenticated ? 403 : 401;
50-
42+
43+
context.Response.StatusCode = context.User is { Identity.IsAuthenticated: true } ? 403 : 401;
5144
return _option.DefaultUnauthorizedOperation?.Invoke(context) ?? Task.CompletedTask;
5245
}
5346
}

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlOptions.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ namespace WeihanLi.Web.AccessControlHelper;
55

66
public sealed class AccessControlOptions
77
{
8+
private Func<HttpContext, string?> _accessKeyResolver = context =>
9+
context.Request.Headers.TryGetValue("X-Access-Key", out var val) ? val.ToString() : null;
810
public bool UseAsDefaultPolicy { get; set; }
911

10-
public Func<HttpContext, string> AccessKeyResolver { get; set; } = context =>
11-
context.Request.Headers.TryGetValue("X-Access-Key", out var val) ? val.ToString() : null;
12+
public Func<HttpContext, string?> AccessKeyResolver
13+
{
14+
get => _accessKeyResolver;
15+
set => _accessKeyResolver = value ?? throw new ArgumentNullException(nameof(AccessKeyResolver));
16+
}
1217

13-
public Func<HttpContext, Task> DefaultUnauthorizedOperation { get; set; }
18+
public Func<HttpContext, Task>? DefaultUnauthorizedOperation { get; set; }
1419
}

src/WeihanLi.Web.Extensions/AccessControlHelper/AccessControlTagHelper.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,12 @@ namespace WeihanLi.Web.AccessControlHelper;
1111
/// https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring?view=aspnetcore-2.1#condition-tag-helper
1212
/// </summary>
1313
[HtmlTargetElement(Attributes = "asp-access")]
14-
public sealed class AccessControlTagHelper : TagHelper
14+
public sealed class AccessControlTagHelper(IControlAccessStrategy controlAccessStrategy) : TagHelper
1515
{
16-
private readonly IControlAccessStrategy _controlAccessStrategy;
17-
18-
public AccessControlTagHelper(IControlAccessStrategy controlAccessStrategy)
19-
{
20-
_controlAccessStrategy = controlAccessStrategy;
21-
}
22-
2316
public override void Process(TagHelperContext context, TagHelperOutput output)
2417
{
2518
context.AllAttributes.TryGetAttribute("asp-access-key", out var accessKey);
26-
if (!_controlAccessStrategy.IsControlCanAccess(accessKey?.Value.ToString()))
19+
if (!controlAccessStrategy.IsControlCanAccess(accessKey?.Value.ToString()))
2720
{
2821
output.SuppressOutput();
2922
}

src/WeihanLi.Web.Extensions/AccessControlHelper/HtmlHelperExtension.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ public static class HtmlHelperExtension
2020
/// <param name="htmlAttributes">htmlAttributes</param>
2121
/// <param name="accessKey">accessKey</param>
2222
/// <returns></returns>
23-
public static IHtmlContent SparkActionLink(this IHtmlHelper helper, string linkText, string actionName, string controllerName = "", object routeValues = null, object htmlAttributes = null, string accessKey = "")
23+
public static IHtmlContent SparkActionLink(
24+
this IHtmlHelper helper, string linkText, string actionName, string? controllerName = null,
25+
object? routeValues = null, object? htmlAttributes = null, string? accessKey = null)
2426
{
2527
if (helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IControlAccessStrategy>()
2628
.IsControlCanAccess(accessKey))
@@ -45,18 +47,22 @@ public static IHtmlContent SparkActionLink(this IHtmlHelper helper, string linkT
4547
/// <param name="attributes">htmlAttributes</param>
4648
/// <param name="accessKey">accessKey</param>
4749
/// <returns></returns>
48-
public static SparkContainer SparkContainer(this IHtmlHelper helper, string tagName, object attributes = null, string accessKey = null)
50+
public static SparkContainer SparkContainer(this IHtmlHelper helper, string tagName, object? attributes = null, string? accessKey = null)
4951
=> SparkContainerHelper(helper, tagName, HtmlHelper.AnonymousObjectToHtmlAttributes(attributes), accessKey);
5052

5153
private static SparkContainer SparkContainerHelper(IHtmlHelper helper, string tagName,
52-
IDictionary<string, object> attributes = null, string accessKey = null)
54+
IDictionary<string, object?>? attributes = null, string? accessKey = null)
5355
{
5456
var tagBuilder = new TagBuilder(tagName);
5557
var canAccess = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IControlAccessStrategy>()
5658
.IsControlCanAccess(accessKey);
5759
if (canAccess)
5860
{
59-
tagBuilder.MergeAttributes(attributes);
61+
if (attributes is not null)
62+
{
63+
tagBuilder.MergeAttributes(attributes);
64+
}
65+
6066
tagBuilder.TagRenderMode = TagRenderMode.StartTag;
6167
helper.ViewContext.Writer.Write(tagBuilder);
6268
}

src/WeihanLi.Web.Extensions/AccessControlHelper/IControlAccessStrategy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ public interface IControlAccessStrategy
1111
/// <summary>
1212
/// view component access strategy
1313
/// </summary>
14-
bool IsControlCanAccess(string accessKey);
14+
bool IsControlCanAccess(string? accessKey);
1515
}

src/WeihanLi.Web.Extensions/AccessControlHelper/IResourceAccessStrategy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public interface IResourceAccessStrategy
1212
/// </summary>
1313
/// <param name="accessKey">accessKey</param>
1414
/// <returns></returns>
15-
bool IsCanAccess(string accessKey);
15+
bool IsCanAccess(string? accessKey);
1616

1717
/// <summary>
1818
/// AccessStrategyName

0 commit comments

Comments
 (0)