mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
Cli: Add HTTP Basic Auth
This commit is contained in:
parent
e01d12c36a
commit
4d0e52c87d
|
@ -39,7 +39,8 @@ namespace BililiveRecorder.Cli
|
|||
var cmd_run = new Command("run", "Run BililiveRecorder in standard mode")
|
||||
{
|
||||
new Option<string?>(new []{ "--http-bind", "--bind", "-b" }, () => null, "Bind address for http service"),
|
||||
// new Option<int?>(new []{ "--http-port", "--port", "-p" }, () => null, "Port number for http service"),
|
||||
new Option<string?>(new []{ "--http-basic-user" }, () => null, "Web interface username"),
|
||||
new Option<string?>(new []{ "--http-basic-pass" }, () => null, "Web interface password"),
|
||||
new Option<LogEventLevel>(new []{ "--loglevel", "--log", "-l" }, () => LogEventLevel.Information, "Minimal log level output to console"),
|
||||
new Option<LogEventLevel>(new []{ "--logfilelevel", "--flog" }, () => LogEventLevel.Debug, "Minimal log level output to file"),
|
||||
new Option<string?>(new []{ "--cert-pem-path", "--pem" }, "Path of the certificate pem file"),
|
||||
|
@ -55,7 +56,8 @@ namespace BililiveRecorder.Cli
|
|||
var cmd_portable = new Command("portable", "Run BililiveRecorder in config-less mode")
|
||||
{
|
||||
new Option<string?>(new []{ "--http-bind", "--bind", "-b" }, () => null, "Bind address for http service"),
|
||||
// new Option<int?>(new []{ "--http-port", "--port", "-p" }, () => null, "Port number for http service"),
|
||||
new Option<string?>(new []{ "--http-basic-user" }, () => null, "Web interface username"),
|
||||
new Option<string?>(new []{ "--http-basic-pass" }, () => null, "Web interface password"),
|
||||
new Option<LogEventLevel>(new []{ "--loglevel", "--log", "-l" }, () => LogEventLevel.Information, "Minimal log level output to console"),
|
||||
new Option<LogEventLevel>(new []{ "--logfilelevel", "--flog" }, () => LogEventLevel.Debug, "Minimal log level output to file"),
|
||||
new Option<string?>(new []{ "--cert-pem-path", "--pem" }, "Path of the certificate pem file"),
|
||||
|
@ -170,6 +172,11 @@ namespace BililiveRecorder.Cli
|
|||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton(recorderAccessProxy);
|
||||
|
||||
if (sharedArguments.HttpBasicUser is not null || sharedArguments.HttpBasicPass is not null)
|
||||
{
|
||||
services.AddSingleton(new BasicAuthCredential(sharedArguments.HttpBasicUser ?? string.Empty, sharedArguments.HttpBasicPass ?? string.Empty));
|
||||
}
|
||||
})
|
||||
.ConfigureWebHost(webBuilder =>
|
||||
{
|
||||
|
@ -419,7 +426,9 @@ namespace BililiveRecorder.Cli
|
|||
|
||||
public string? HttpBind { get; set; } = null;
|
||||
|
||||
// public int? HttpPort { get; set; } = null;
|
||||
public string? HttpBasicUser { get; set; } = null;
|
||||
|
||||
public string? HttpBasicPass { get; set; } = null;
|
||||
|
||||
public string? CertPemPath { get; set; } = null;
|
||||
|
||||
|
|
19
BililiveRecorder.Web/BasicAuthCredential.cs
Normal file
19
BililiveRecorder.Web/BasicAuthCredential.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
public class BasicAuthCredential
|
||||
{
|
||||
public BasicAuthCredential(string username, string password)
|
||||
{
|
||||
this.Username = username ?? throw new ArgumentNullException(nameof(username));
|
||||
this.Password = password ?? throw new ArgumentNullException(nameof(password));
|
||||
this.EncoededValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
|
||||
}
|
||||
|
||||
public string Username { get; }
|
||||
public string Password { get; }
|
||||
public string EncoededValue { get; }
|
||||
}
|
||||
}
|
75
BililiveRecorder.Web/BasicAuthMiddleware.cs
Normal file
75
BililiveRecorder.Web/BasicAuthMiddleware.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
public class BasicAuthMiddleware
|
||||
{
|
||||
private readonly RequestDelegate next;
|
||||
private readonly ManifestEmbeddedFileProvider fileProvider;
|
||||
private readonly BasicAuthCredential? credential;
|
||||
private const string BasicAndSpace = "Basic ";
|
||||
|
||||
private static string? Html401Page;
|
||||
|
||||
public BasicAuthMiddleware(RequestDelegate next, ManifestEmbeddedFileProvider fileProvider, BasicAuthCredential? credential)
|
||||
{
|
||||
this.next = next ?? throw new ArgumentNullException(nameof(next));
|
||||
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
|
||||
this.credential = credential;
|
||||
}
|
||||
|
||||
public Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
if (this.credential is null)
|
||||
{
|
||||
// 没有启用身份验证
|
||||
return this.next(context);
|
||||
}
|
||||
|
||||
string headerValue = context.Request.Headers["Authorization"];
|
||||
if (string.IsNullOrEmpty(headerValue) ||
|
||||
!headerValue.StartsWith(BasicAndSpace, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return this.ResponseWith401Async(context);
|
||||
}
|
||||
|
||||
var requestCredential = headerValue[BasicAndSpace.Length..].Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(requestCredential))
|
||||
{
|
||||
return this.ResponseWith401Async(context);
|
||||
}
|
||||
|
||||
if (this.credential.EncoededValue.Equals(requestCredential, StringComparison.Ordinal))
|
||||
{
|
||||
return this.next(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.ResponseWith401Async(context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ResponseWith401Async(HttpContext context)
|
||||
{
|
||||
context.Response.StatusCode = 401;
|
||||
context.Response.ContentType = "text/html";
|
||||
context.Response.Headers.Append(HeaderNames.WWWAuthenticate, $"{BasicAndSpace}realm=\"BililiveRecorder {GitVersionInformation.FullSemVer}\"");
|
||||
|
||||
if (Html401Page is null)
|
||||
{
|
||||
using var file = this.fileProvider.GetFileInfo("/401.html").CreateReadStream();
|
||||
using var reader = new StreamReader(file);
|
||||
var str = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
Html401Page = str.Replace("__VERSION__", GitVersionInformation.FullSemVer).Replace("__FULL_VERSION__", GitVersionInformation.InformationalVersion);
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync(Html401Page, System.Text.Encoding.UTF8).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -122,6 +122,8 @@ namespace BililiveRecorder.Web
|
|||
{
|
||||
const string PAGE404 = "/404.html";
|
||||
|
||||
app.UseMiddleware<BasicAuthMiddleware>();
|
||||
|
||||
app.UseCors().UseWebSockets();
|
||||
|
||||
app.Use(static next => async context =>
|
||||
|
|
19
BililiveRecorder.Web/embeded/401.html
Normal file
19
BililiveRecorder.Web/embeded/401.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<meta name="robots" content="noindex">
|
||||
<meta content="width=device-width,initial-scale=1" name=viewport>
|
||||
<title>401 未登录 - B站录播姬 __VERSION__</title>
|
||||
<style>*{text-align:center;}p{font-size:10px;}</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="color:red;font-weight:bold;font-size:3em;">HTTP 401</h1>
|
||||
<p title="__FULL_VERSION__">
|
||||
<a href="https://rec.danmuji.org">B站录播姬</a> __VERSION__
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user