feat: 更新

main
bicijinlian 2 years ago
parent 53eab0dabf
commit c65317f18f

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -17,8 +17,6 @@ namespace AuthStudy.Authentication.Basic
{
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
private const string _Scheme = "BasicScheme";
private readonly UTF8Encoding _utf8ValidatingEncoding = new UTF8Encoding(false, true);
public BasicAuthenticationHandler
@ -42,69 +40,21 @@ namespace AuthStudy.Authentication.Basic
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
string? authorizationHeader = Request.Headers["Authorization"];
if (string.IsNullOrEmpty(authorizationHeader))
{
return AuthenticateResult.NoResult();
}
string requestBasicText = GetRequestBasic();
// Exact match on purpose, rather than using string compare
// asp.net request parsing will always trim the header and remove trailing spaces
if (_Scheme == authorizationHeader)
//认证信息
var basicInfo = ParseBasicInfo(requestBasicText);
if (!basicInfo.ParseResult)
{
const string noCredentialsMessage = "Authorization scheme was Basic but the header had no credentials.";
Logger.LogInformation(noCredentialsMessage);
return AuthenticateResult.Fail(noCredentialsMessage);
return AuthenticateResult.Fail(basicInfo.Message);
}
if (!authorizationHeader.StartsWith(_Scheme + ' ', StringComparison.OrdinalIgnoreCase))
{
return AuthenticateResult.NoResult();
}
string encodedCredentials = authorizationHeader.Substring(_Scheme.Length).Trim();
try
{
string decodedCredentials = string.Empty;
byte[] base64DecodedCredentials;
try
{
base64DecodedCredentials = Convert.FromBase64String(encodedCredentials);
}
catch (FormatException)
{
const string failedToDecodeCredentials = "Cannot convert credentials from Base64.";
Logger.LogInformation(failedToDecodeCredentials);
return AuthenticateResult.Fail(failedToDecodeCredentials);
}
try
{
decodedCredentials = _utf8ValidatingEncoding.GetString(base64DecodedCredentials);
}
catch (Exception ex)
{
const string failedToDecodeCredentials = "Cannot build credentials from decoded base64 value, exception {ex.Message} encountered.";
Logger.LogInformation(failedToDecodeCredentials, ex.Message);
return AuthenticateResult.Fail(ex.Message);
}
var delimiterIndex = decodedCredentials.IndexOf(":", StringComparison.OrdinalIgnoreCase);
if (delimiterIndex == -1)
{
const string missingDelimiterMessage = "Invalid credentials, missing delimiter.";
Logger.LogInformation(missingDelimiterMessage);
return AuthenticateResult.Fail(missingDelimiterMessage);
}
var username = decodedCredentials.Substring(0, delimiterIndex);
var password = decodedCredentials.Substring(delimiterIndex + 1);
var validateCredentialsContext = new ValidateCredentialsContext(Context, Scheme, Options)
{
Username = username,
Password = password
Username = basicInfo.UserName,
Password = basicInfo.Password
};
if (Events != null)
@ -113,10 +63,9 @@ namespace AuthStudy.Authentication.Basic
}
if (validateCredentialsContext.Result != null &&
validateCredentialsContext.Result.Succeeded)
if (validateCredentialsContext.Result != null && validateCredentialsContext.Result.Succeeded)
{
var ticket = new AuthenticationTicket(validateCredentialsContext.Principal, Scheme.Name);
var ticket = new AuthenticationTicket(validateCredentialsContext.Principal!, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
@ -151,9 +100,16 @@ namespace AuthStudy.Authentication.Basic
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
//如果响应已经开始,则忽略
//比如同时使用其它认证,失败后已经被设置了
if (Response.HasStarted)
{
return Task.CompletedTask;
}
if (!Request.IsHttps && !Options.AllowInsecureProtocol)
{
const string insecureProtocolMessage = "Request is HTTP, Basic Authentication will not respond.";
const string insecureProtocolMessage = "请求为HTTP基本身份验证将不响应。";
Logger.LogInformation(insecureProtocolMessage);
Response.StatusCode = StatusCodes.Status421MisdirectedRequest;
}
@ -162,12 +118,106 @@ namespace AuthStudy.Authentication.Basic
Response.StatusCode = 401;
if (!Options.SuppressWWWAuthenticateHeader)
{
var headerValue = _Scheme + $" realm=\"{Options.Realm}\"";
var headerValue = BasicAuthenticationDefaults.AuthenticationScheme + $" realm=\"{Options.Realm}\"";
Response.Headers.Append(HeaderNames.WWWAuthenticate, headerValue);
}
}
return Task.CompletedTask;
}
private string GetRequestBasic()
{
//请求头接收
string basicText = Request.Headers["Authorization"].ToString();
if (string.IsNullOrWhiteSpace(basicText))
{
basicText = Request.Headers["Authorization"].ToString();
}
//URL参数
if (string.IsNullOrWhiteSpace(basicText))
{
basicText = $"{Request.Query["Basic"]}";
}
//URL参数
if (string.IsNullOrWhiteSpace(basicText))
{
basicText = $"{Request.Query["User"]}:{Request.Query["Password"]}";
basicText = basicText.TrimStart(':');
}
return basicText;
}
private (bool ParseResult, string Message, string UserName, string Password) ParseBasicInfo(string requestBasic)
{
(bool ParseResult, string Message, string UserName, string Password) result = (true, "格式错误", "", "");
if (string.IsNullOrWhiteSpace(requestBasic))
{
result.Message = "无认证信息";
return result;
}
requestBasic = requestBasic.Trim();
if (requestBasic.Equals("Basic", StringComparison.OrdinalIgnoreCase))
{
result.Message = "授权方案是Basic但标头没有内容!";
return result;
}
var basicList = requestBasic.Split(':');
if (basicList.Length == 2)
{
result.ParseResult = true;
result.Message = "认证信息正确";
result.UserName = basicList[0];
result.Password = basicList[1];
return result;
}
requestBasic = requestBasic.Replace("Basic ", "", StringComparison.OrdinalIgnoreCase);
string decodedCredentials = string.Empty;
byte[] base64DecodedCredentials;
try
{
base64DecodedCredentials = Convert.FromBase64String(requestBasic);
}
catch (FormatException)
{
result.ParseResult = false;
result.Message = "凭据不是Base64格式";
return result;
}
try
{
decodedCredentials = _utf8ValidatingEncoding.GetString(base64DecodedCredentials);
}
catch (Exception ex)
{
result.ParseResult = false;
result.Message = $"认证信息生成凭据时异常:{ex.Message}";
return result;
}
var list = decodedCredentials.Split(':');
if (list.Length != 2)
{
result.ParseResult = false;
result.Message = $"凭据无效,缺少分隔符!";
return result;
}
result.ParseResult = true;
result.Message = "认证信息正确";
result.UserName = list[0];
result.Password = list[1];
return result;
}
}
}

@ -61,7 +61,7 @@ namespace AuthStudy.Authentication.Basic
public bool AllowInsecureProtocol
{
get; set;
}
} = true;
/// <summary>
/// 事件

@ -1,6 +1,7 @@
using AuthStudy.Authentication.Browser;
using AuthStudy.WebApp.VModels;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -16,14 +17,18 @@ namespace AuthStudy.WebApp.Controllers
}
//多特性是and特性内逗号分隔是or
//[Authorize]
//[Authorize(AuthenticationSchemes = AuthenticationSchemeList.BaseBrowserScheme)]
//[Authorize(AuthenticationSchemes = AuthenticationSchemeList.BrowserScheme)]
//[Authorize(AuthenticationSchemes = AuthenticationSchemeList.BasicScheme)]
[Authorize(AuthenticationSchemes = $"{AuthenticationSchemeList.BaseBrowserScheme},{AuthenticationSchemeList.BrowserScheme},{AuthenticationSchemeList.BasicScheme}")]
//[Authorize]
//[Authorize(AuthenticationSchemes = $"{AuthenticationSchemeList.BrowserScheme},{AuthenticationSchemeList.BasicScheme}")]
//[Authorize(AuthenticationSchemes = $"{AuthenticationSchemeList.BaseBrowserScheme},{AuthenticationSchemeList.BrowserScheme},{AuthenticationSchemeList.BasicScheme}")]
[HttpGet]
public IActionResult GetAll()
public async Task<IActionResult> GetAll()
{
var dd = await HttpContext.AuthenticateAsync();
//输出认证信息
foreach (var claim in User.Claims)
{

@ -1,5 +1,8 @@
using System.Security.Claims;
using AuthStudy.Authentication.Basic;
using AuthStudy.Authentication.Basic.Events;
using AuthStudy.Authentication.Browser;
namespace AuthStudy.WebApp
@ -34,7 +37,30 @@ namespace AuthStudy.WebApp
option.AllowBrowsers = new List<string>() { "Edge", "Chrome", "Firefox" };
})
//基本认证
.AddBasic(AuthenticationSchemeList.BasicScheme);
.AddBasic(options =>
{
options.Realm = "Basic Authentication";
options.Events = new BasicAuthenticationEvents
{
OnValidateCredentials = context =>
{
if (context.Username == context.Password)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, context.Username, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.Username, ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
return Task.CompletedTask;
}
};
});
//默认基类实现注册
@ -52,6 +78,11 @@ namespace AuthStudy.WebApp
app.MapControllers();
app.Run();
void Test()
{
}
}
}
}
Loading…
Cancel
Save