0
点赞
收藏
分享

微信扫一扫

ASP.NET Core 实现自定义认证 #yyds干货盘点#

前言

在 ASP.NET Core 中,我们常使用基于 JWT 的认证:

services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtToken:Issuer"],
ValidAudience = Configuration["JwtToken:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtToken:SecretKey"]))
};
});

但有时候,我们需要使用自定义认证,比如使用QueryString(htttp://xxx?_key=xxx),只要请求中包含的​​_key​​的值正确即可。

AddJwtBearer 实现原理

为了实现自定义认证,我们决定仿照​​AddJwtBearer​​的实现机制。

​AddJwtBearer​​​实际执行的是​​AddScheme​​方法:

public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, string? displayName, Action<JwtBearerOptions> configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, JwtBearerPostConfigureOptions>());
return builder.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, displayName, configureOptions);
}

​JwtBearerHandler​​​是具体的处理程序,继承自​​AuthenticationHandler<TOptions>​​​,主要代码在​​HandleAuthenticateAsync​​内:

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
...

if (string.IsNullOrEmpty(token))
{
string authorization = Request.Headers.Authorization.ToString();

// If no authorization header found, nothing to process further
if (string.IsNullOrEmpty(authorization))
{
return AuthenticateResult.NoResult();
}

if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
token = authorization.Substring("Bearer ".Length).Trim();
}

// If no token found, no further work possible
if (string.IsNullOrEmpty(token))
{
return AuthenticateResult.NoResult();
}
}

...

foreach (var validator in Options.SecurityTokenValidators)
{
if (validator.CanReadToken(token))
{
...

var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options)
{
Principal = principal,
SecurityToken = validatedToken
};

...

tokenValidatedContext.Success();
return tokenValidatedContext.Result!;
}
}

...
}

从​​Request.Headers.Authorization​​​获取token,然后用​​Options.SecurityTokenValidators​​验证token合法后,返回结果。

Demo

DemoAuthenticationOptions

创建​​DemoAuthenticationOptions​​​,继承自​​AuthenticationSchemeOptions​​:

public class DemoAuthenticationOptions : AuthenticationSchemeOptions
{
public const string Scheme = "Demo";
}

DemoAuthenticationHandler

创建​​DemoAuthenticationHandler​​​,继承自​​AuthenticationHandler<DemoAuthenticationOptions>​​:

public class DemoAuthenticationHandler : AuthenticationHandler<DemoAuthenticationOptions>
{
public DemoAuthenticationHandler(IOptionsMonitor<DemoAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
throw new NotImplementedException();
}
}

实现 HandleAuthenticateAsync 方法

从请求的​​Query​​​中获取​​key​​,然后检查是否合法:

protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Query.TryGetValue("_key", out var keys))
{
return AuthenticateResult.NoResult();
}

var key = keys.FirstOrDefault();

//到数据库检索
if (key =="123456")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "My IO")
};

var identity = new ClaimsIdentity(claims, DemoAuthenticationOptions.Scheme);
var identities = new List<ClaimsIdentity> { identity };
var principal = new ClaimsPrincipal(identities);
var ticket = new AuthenticationTicket(principal, DemoAuthenticationOptions.Scheme);

return AuthenticateResult.Success(ticket);
}

return AuthenticateResult.NoResult();
}

定义扩展方法

定义扩展方法,使用我们上面创建的​​DemoAuthenticationHandler​​:

public static class AuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddDemoAuthentication(this AuthenticationBuilder authenticationBuilder, Action<DemoAuthenticationOptions> options)
{
return authenticationBuilder.AddScheme<DemoAuthenticationOptions, DemoAuthenticationHandler>(DemoAuthenticationOptions.Scheme, options);
}
}

使用

修改Startup.cs:

services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = DemoAuthenticationOptions.Scheme;
option.DefaultChallengeScheme = DemoAuthenticationOptions.Scheme;

})
.AddDemoAuthentication(options => { });

结论

当不加​​Query​​​或使用错误的​​key​​时,返回401 认证失败:

ASP.NET Core 实现自定义认证 #yyds干货盘点#_ide

仅当使用正确的​​key​​时,API 访问成功:

ASP.NET Core 实现自定义认证 #yyds干货盘点#_自定义_02

想了解更多内容,请关注我的个人公众号”My IO“ASP.NET Core 实现自定义认证 #yyds干货盘点#_ide_03

举报

相关推荐

0 条评论