我是靠谱客的博主 狂野水杯,最近开发中收集的这篇文章主要介绍asp.net自定义认证(1)Program.csAuthenticationHandler自定义认证处理器控制器代码实验结果 ,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
自定义认证
- Program.cs
- AuthenticationHandler<TOptions>
- 自定义认证处理器
- 控制器代码
- 实验结果
Program.cs
主要看AddAuthentication,AddScheme,UseAuthentication,UseAuthorization
using CustomAuthentication.AuthenticationHandlers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//AddAuthentication的参数为默认方案名,该方案任何情况下都会执行(如果明确指定方案的话,代码会执行,但不影响最终认证结果)
//SecretAuthenticationOptions(自定义)继承自AuthenticationSchemeOptions,可自定义一些选项
//SecretAuthenticationHandler(自定义)继承自AuthenticationHandler<SecretAuthenticationOptions>,实现具体认证过程
//AddScheme的第一个参数为自定义方案名,第二个参数可配置SecretAuthenticationOptions
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();
//若Options.ForwardChallenge没有指定挑战方案
//则在认证失败的情况下执行该方法,以下是默认实现
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);
}
}
//若Options.ForwardForbid没有指定授权失败方案
//则在认证成功但授权失败的情况下执行该方法,以下是默认实现
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 = { "小明", "小李", "小华" };
//具体认证过程
//若该方案是默认方案,无论任何时候(action存不存在,有没有标注Authorize特性),该方法都会执行(如果明确指定方案的话,代码会执行,但不影响最终认证结果)
//若不是默认方案,则仅在标注了Authorize特性,并指定了该方案的情况下,该方法才会执行
//若认证成功,会将返回值中的claimsPrincipal赋值给HttpContext.User,后续在action中可以访问
//ClaimTypes.Role为预定义的Claim类型
//ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
protected override Task<AuthenticateResult> HandleAuthenticateAsync() => Request.Query["name"] switch
{
//认证成功,角色设置为小红的朋友,name为自定义的额外信息
{ Count: 1 } s when xiaohongFriends.Contains(s.ToString()) => createSingleIdentityAuthenticationTicket(new[]
{
new Claim(ClaimTypes.Role, SecretRoles.XiaoHongFriend),
new Claim("name", s.ToString())
}),
//认证成功,角色设置为小红的爱慕者,name为自定义的额外信息
{ 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
{
//若未指定AuthenticationSchemes,则仅有默认方案会执行(如果明确指定方案的话,代码会执行,但不影响最终认证结果)
//AuthenticationSchemes可指定多个方案,用逗号分割,从左到右执行所有认证方案,若全部认证失败则失败,否则认证成功,并且合并所有结果返回(默认方案总是第一个执行,但不影响认证结果)
//挑战方案和授权失败方案由最后一个方案提供
//这里使用的是基于角色的访问控制(RBAC),限制了只有小红的朋友才能访问该action
[Authorize(AuthenticationSchemes = SecretAuthenticationOptions.Scheme, Roles = SecretRoles.XiaoHongFriend)]
[HttpGet]
public string Secret1()
{
//User为ClaimsPrincipal类型,认证成功后会为其赋值(没有认证该值也不是null,是个空对象)
//从中寻找类型为name的Claim信息
return $"{HttpContext.User.FindFirst("name")?.Value ?? "无名"}知道了小明喜欢小红";
}
}
实验结果
- 认证失败(默认401响应)
- 认证成功但授权失败(默认403响应)
- 授权成功
最后
以上就是狂野水杯为你收集整理的asp.net自定义认证(1)Program.csAuthenticationHandler
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复