Program.cs
主要看AddAuthentication,AddScheme,UseAuthentication,UseAuthorization
using CustomAuthentication.AuthenticationHandlers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(SecretAuthenticationOptions.Scheme)
.AddScheme<SecretAuthenticationOptions, SecretAuthenticationHandler>(SecretAuthenticationOptions.Scheme, options => {} );
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
AuthenticationHandler<TOptions>
public abstract class AuthenticationHandler<TOptions> : IAuthenticationHandler
where TOptions : AuthenticationSchemeOptions, new()
{
protected abstract Task<AuthenticateResult> HandleAuthenticateAsync();
protected virtual Task HandleChallengeAsync(AuthenticationProperties properties)
{
this.Response.StatusCode = 401;
return Task.CompletedTask;
}
public async Task ChallengeAsync(AuthenticationProperties? properties)
{
string scheme = this.ResolveTarget(this.Options.ForwardChallenge);
if (scheme != null)
{
await this.Context.ChallengeAsync(scheme, properties);
}
else
{
if (properties == null)
properties = new AuthenticationProperties();
await this.HandleChallengeAsync(properties);
this.Logger.AuthenticationSchemeChallenged(this.Scheme.Name);
}
}
protected virtual Task HandleForbiddenAsync(AuthenticationProperties properties)
{
this.Response.StatusCode = 403;
return Task.CompletedTask;
}
public async Task ForbidAsync(AuthenticationProperties? properties)
{
string scheme = this.ResolveTarget(this.Options.ForwardForbid);
if (scheme != null)
{
await this.Context.ForbidAsync(scheme, properties);
}
else
{
if (properties == null)
properties = new AuthenticationProperties();
await this.HandleForbiddenAsync(properties);
this.Logger.AuthenticationSchemeForbidden(this.Scheme.Name);
}
}
}
自定义认证处理器
ClaimsPrincipal :人(User)
ClaimsIdentity : 人拥有的证件,例如身份证(人可以拥有多张证件)
Claims : 证件上的信息,例如姓名,出生日期
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
namespace CustomAuthentication.AuthenticationHandlers;
public class SecretAuthenticationOptions : AuthenticationSchemeOptions
{
public const string Scheme = "Secret";
}
public static class SecretRoles
{
public const string XiaoHongFriend = "XiaoHongFriend";
public const string XiaoHongAdorer = "XiaoHongAdorer";
}
public class SecretAuthenticationHandler : AuthenticationHandler<SecretAuthenticationOptions>
{
public SecretAuthenticationHandler(IOptionsMonitor<SecretAuthenticationOptions> options, ILoggerFactory logger,
UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
private Task<AuthenticateResult> createSingleIdentityAuthenticationTicket(IEnumerable<Claim> claims)
{
var claimsPrincipal = new ClaimsPrincipal();
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaims(claims);
claimsPrincipal.AddIdentity(claimsIdentity);
return Task.FromResult(
AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, SecretAuthenticationOptions.Scheme)));
}
private string[] xiaohongFriends = { "小红", "小芳", "小樱" };
private string[] xiaohongAdorers = { "小明", "小李", "小华" };
protected override Task<AuthenticateResult> HandleAuthenticateAsync() => Request.Query["name"] switch
{
{ Count: 1 } s when xiaohongFriends.Contains(s.ToString()) => createSingleIdentityAuthenticationTicket(new[]
{
new Claim(ClaimTypes.Role, SecretRoles.XiaoHongFriend),
new Claim("name", s.ToString())
}),
{ Count: 1 } s when xiaohongAdorers.Contains(s.ToString()) => createSingleIdentityAuthenticationTicket(new[]
{
new Claim(ClaimTypes.Role, SecretRoles.XiaoHongAdorer),
new Claim("name", s.ToString())
}),
_ => Task.FromResult(AuthenticateResult.NoResult())
};
}
控制器代码
using CustomAuthentication.AuthenticationHandlers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CustomAuthentication.Controllers;
[Route("[controller]/[action]")]
public class SecretSpaceController : ControllerBase
{
[Authorize(AuthenticationSchemes = SecretAuthenticationOptions.Scheme, Roles = SecretRoles.XiaoHongFriend)]
[HttpGet]
public string Secret1()
{
return $"{HttpContext.User.FindFirst("name")?.Value ?? "无名"}知道了小明喜欢小红";
}
}
实验结果