欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 为CAP面板天添加简单的认证功能 C#|.net

为CAP面板天添加简单的认证功能 C#|.net

2024/10/24 8:24:59 来源:https://blog.csdn.net/u010182162/article/details/139630791  浏览:    关键词:为CAP面板天添加简单的认证功能 C#|.net

做过后端的比较熟悉,CAP面板有个界面,可以通过域名加cap访问:

但是这个面板直接通过url就可以访问了。

Hangfire Dashboard有自己的面板,可以使用用户名和密码做简单的认证。

LogDashboard也有自己的面板,可以使用用户名和密码做简单的认证。

如下图:

但是CAP的面板是裸露的,没有直接的认证功能。

官方提供了文档,但是没有简单的用户名和密码的认证示例。

https://cap.dotnetcore.xyz/user-guide/zh/monitoring/dashboard/

简单到不知道它在表达什么:

于是只能自己摸索了。

CAP面板引用的包:

DotNetCore.CAP.Dashboard

认证需要另外引用一个包:

Microsoft.AspNetCore.Authentication

然后创建自己的认证处理器:

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;namespace Extensions
{/// <summary>/// 自定义面板认证/// </summary>public static class MyAuthDefaults{/// <summary>/// 自定义面板认证-协议名/// </summary>public const string Policy = "MyAuthPolicy";/// <summary>/// 自定义面板认证-方案名/// </summary>public const string Scheme = "MyAuthScheme";}/// <summary>/// 自定义面板认证配置/// </summary>public class MyAuthSchemeOptions : AuthenticationSchemeOptions { }/// <summary>/// 自定义面板认证处理器/// </summary>public class MyAuthHandler : AuthenticationHandler<MyAuthSchemeOptions>{/// <summary>/// 自定义面板认证处理器/// </summary>public MyAuthHandler(IOptionsMonitor<MyAuthSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock){}/// <summary>/// 自定义面板认证-验证/// </summary>protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){AuthenticateResult authResult = null;if (!Request.Headers.ContainsKey("Authorization")){authResult = AuthenticateResult.NoResult();return await Task.FromResult(authResult);}try{var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);var credentialsBytes = Convert.FromBase64String(authHeader.Parameter);var credentials = Encoding.UTF8.GetString(credentialsBytes).Split(':');var username = credentials[0];var password = credentials[1];if (username != "admin" || password != "123456"){authResult = AuthenticateResult.Fail("Invalid Username or Password");return await Task.FromResult(authResult);}var claims = new[] {new Claim(ClaimTypes.NameIdentifier, username),new Claim(ClaimTypes.Name, username),};var identity = new ClaimsIdentity(claims, Scheme.Name);var principal = new ClaimsPrincipal(identity);var ticket = new AuthenticationTicket(principal, Scheme.Name);authResult = AuthenticateResult.Success(ticket);return await Task.FromResult(authResult);}catch (Exception ex){authResult = AuthenticateResult.Fail("Invalid Authorization Header");return await Task.FromResult(authResult);}}/// <summary>/// 自定义面板认证-变动/// </summary>protected override Task HandleChallengeAsync(AuthenticationProperties properties){Response.StatusCode = 401;Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{Scheme.Name}\", charset=\"UTF-8\"";return base.HandleChallengeAsync(properties);}}
}

代码里面设置了默认账号:

admin/123456

如果账号来自config配置,则需要做如下修改:

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;namespace Extensions
{/// <summary>/// 自定义面板认证/// </summary>public static class MyAuthDefaults{/// <summary>/// 自定义面板认证-协议名/// </summary>public const string Policy = "MyAuthPolicy";/// <summary>/// 自定义面板认证-方案名/// </summary>public const string Scheme = "MyAuthScheme";}/// <summary>/// 自定义面板认证配置/// </summary>public class MyAuthSchemeOptions : AuthenticationSchemeOptions { }/// <summary>/// 自定义面板认证处理器/// </summary>public class MyAuthHandler : AuthenticationHandler<MyAuthSchemeOptions>{private readonly IConfiguration _configuration;/// <summary>/// 自定义面板认证处理器/// </summary>public MyAuthHandler(IOptionsMonitor<MyAuthSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IConfiguration configuration) : base(options, logger, encoder, clock){_configuration = configuration;}/// <summary>/// 自定义面板认证-验证/// </summary>protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){AuthenticateResult authResult = null;if (!Request.Headers.ContainsKey("Authorization")){authResult = AuthenticateResult.NoResult();return await Task.FromResult(authResult);}try{var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);var credentialsBytes = Convert.FromBase64String(authHeader.Parameter);var credentials = Encoding.UTF8.GetString(credentialsBytes).Split(':');var username = credentials[0];var password = credentials[1];var checkUser = _configuration["Auth:User"];var checkPwd  = _configuration["Auth:Pwd"];if (username != checkUser || password != checkPwd){authResult = AuthenticateResult.Fail("Invalid Username or Password");return await Task.FromResult(authResult);}var claims = new[] {new Claim(ClaimTypes.NameIdentifier, username),new Claim(ClaimTypes.Name, username),};var identity = new ClaimsIdentity(claims, Scheme.Name);var principal = new ClaimsPrincipal(identity);var ticket = new AuthenticationTicket(principal, Scheme.Name);authResult = AuthenticateResult.Success(ticket);return await Task.FromResult(authResult);}catch (Exception ex){authResult = AuthenticateResult.Fail("Invalid Authorization Header");return await Task.FromResult(authResult);}}/// <summary>/// 自定义面板认证-变动/// </summary>protected override Task HandleChallengeAsync(AuthenticationProperties properties){Response.StatusCode = 401;Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{Scheme.Name}\", charset=\"UTF-8\"";return base.HandleChallengeAsync(properties);}}
}

然后创建一个异常处理中间件里面,里面专门针对cap面板的路径做处理:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Extensions;namespace Middleware
{/// <summary>/// 全局异常处理 中间件/// </summary>public class ExceptionHandlerMiddleware{private readonly RequestDelegate next;private readonly ILogger logger;/// <summary>/// 全局异常处理 中间件/// </summary>public ExceptionHandlerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory){this.next = next;logger = loggerFactory.CreateLogger("globeException");}/// <summary>/// 全局异常处理 中间件/// </summary>public async Task Invoke(HttpContext context){try{//CAP面板认证if (context.Request.Path.ToString().ToLower().Contains("/cap/")){var authResult = await context.AuthenticateAsync(MyAuthDefaults.Scheme);if (authResult.Succeeded == false) //认证失败{await context.ChallengeAsync(MyAuthDefaults.Scheme);return;}context.User = authResult.Principal;  //成功后用户信息返回await next(context);  // 如果需要继续处理请求,可以调用下一个中间件return;}else{await next(context);}}catch (Exception ex){string exStr = ex.Message;}}}
}

添加针对面板的扩展:

using Extensions;namespace Extensions
{public static class CapDashboardExtensions{/// <summary>/// 带认证的面板/// </summary>public static void AddCapDashboard(this IServiceCollection services, WebApplicationBuilder builder){services.AddAuthentication(MyAuthDefaults.Scheme).AddScheme<MyAuthSchemeOptions, MyAuthHandler>(MyAuthDefaults.Scheme, options => { });services.AddAuthorization(options =>{options.AddPolicy(MyAuthDefaults.Policy, policy =>{policy.AddAuthenticationSchemes(MyAuthDefaults.Scheme).RequireAuthenticatedUser();});});services.AddCors(options =>{options.AddDefaultPolicy(builder =>{builder.AllowCredentials().AllowAnyHeader().AllowAnyMethod();});});services.AddCap(options =>{options.FailedRetryInterval = 60;options.FailedRetryCount = 50;//需要认证options.UseDashboard(d =>{d.PathMatch = "/Cap";d.UseChallengeOnAuth = true;d.DefaultChallengeScheme = MyAuthDefaults.Scheme;});});}}
}

最后在Program里面加上面板的扩展:


var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
services.AddCapDashboard(builder); //添加Cap面板var app = builder.Build();
app.UseCors();
app.UseAuthentication(); // 启用认证中间件
app.UseAuthorization();

然后项目启动后,域名加上cap:

http://127.0.0.1:80/cap

就可以进入认证界面了:

大功搞成!输入代码里的账号,就可以进入CAP面板了:

因为网上找不到简单的CAP认证实现功能,所以这个功能摸索着开发了好久。

创作不易,给点鼓励,谢谢!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com