Core 1.1 遵循@blowdart 的建议并实现了一个自定义中间件:
https://stackoverflow.com/a/31465227/29821
它是这样工作的:
中间件运行。从请求标头中提取了一个令牌。验证令牌,如果有效,则构建一个包含多个声明的身份 (ClaimsIdentity),然后通过 HttpContext.User.AddIdentity() 添加这些声明;在使用 services.AddAuthorization 的 ConfigureServices 中,我添加了一个策略来要求中间件提供的声明。在控制器/动作中,我将使用 [Authorize(Roles = "some role that the middleware added")]
这有点适用于 2.0,除了如果令牌无效(上面的步骤 2)并且从未添加声明,我会得到“没有指定 authenticationScheme,并且没有找到 DefaultChallengeScheme”。
所以现在我正在阅读 2.0 中更改的身份验证:
https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x
我在 ASP.NET Core 2.0 中做同样事情的正确路径是什么?我没有看到进行真正自定义身份验证的示例。
因此,经过一整天的尝试来解决这个问题,我终于弄清楚了微软希望我们如何为他们在 core 2.0 中的新单中间件设置制作自定义身份验证处理程序。
在浏览了 MSDN 上的一些文档后,我发现了一个名为 AuthenticationHandler<TOption>
的类,它实现了 IAuthenticationHandler
接口。
从那里,我找到了一个完整的代码库,其中包含位于 https://github.com/aspnet/Security 的现有身份验证方案
在其中之一中,它显示了 Microsoft 如何实现 JwtBearer 身份验证方案。 (https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer)
我将大部分代码复制到一个新文件夹中,并清除了与 JwtBearer
相关的所有内容。
在 JwtBearerHandler
类(扩展 AuthenticationHandler<>
)中,有一个 Task<AuthenticateResult> HandleAuthenticateAsync()
的覆盖
我在我们的旧中间件中添加了用于通过自定义令牌服务器设置声明,但仍然遇到一些权限问题,当令牌无效且未设置声明时,只是吐出 200 OK
而不是 401 Unauthorized
。
我意识到我已经覆盖了 Task HandleChallengeAsync(AuthenticationProperties properties)
,无论出于何种原因,它都用于通过控制器中的 [Authorize(Roles="")]
设置权限。
删除此覆盖后,代码有效,并且在权限不匹配时成功抛出了 401
。
主要的收获是现在您不能使用自定义中间件,您必须通过 AuthenticationHandler<>
实现它,并且在使用 services.AddAuthentication(...)
时必须设置 DefaultAuthenticateScheme
和 DefaultChallengeScheme
。
这是一个应该是什么样子的示例:
在 Startup.cs / ConfigureServices() 添加:
services.AddAuthentication(options =>
{
// the scheme name has to match the value we're going to use in AuthenticationBuilder.AddScheme(...)
options.DefaultAuthenticateScheme = "Custom Scheme";
options.DefaultChallengeScheme = "Custom Scheme";
})
.AddCustomAuth(o => { });
在 Startup.cs / Configure() 添加:
app.UseAuthentication();
创建一个新文件 CustomAuthExtensions.cs
public static class CustomAuthExtensions
{
public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action<CustomAuthOptions> configureOptions)
{
return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("Custom Scheme", "Custom Auth", configureOptions);
}
}
创建一个新文件 CustomAuthOptions.cs
public class CustomAuthOptions: AuthenticationSchemeOptions
{
public CustomAuthOptions()
{
}
}
创建一个新文件 CustomAuthHandler.cs
internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
// store custom services here...
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// build the claims and put them in "Context"; you need to import the Microsoft.AspNetCore.Authentication package
return AuthenticateResult.NoResult();
}
}
正如您参考的文章所指出的那样,从 Core 1.x 到 Core 2.0 的 Identity 发生了相当大的变化。主要变化是摆脱中间件方法并使用依赖注入来配置自定义服务。这为更复杂的实现自定义身份提供了更大的灵活性。因此,您希望摆脱上面提到的中间件方法并转向服务。按照参考文章中的迁移步骤来实现此目标。首先将 app.UseIdentity 替换为 app.UseAuthentication。 UseIdentity 已弃用,未来版本将不再支持。有关如何插入自定义声明转换并对声明执行授权的完整示例 view this blog post。
不定期副业成功案例分享
DefaultAuthenticateScheme
和DefaultChallengeScheme
吗?我不明白为什么它们都被使用?以及它们之间有什么区别。AuthExtension
需要位于Microsoft.Extensions.DependencyInjection
命名空间内。请参阅此示例:github.com/aspnet/Security/blob/rel/2.0.0/src/…