众所周知,在ASP.NETWebAPI中,认证是通过AuthenticationFilter过滤器实现的,我们通常的做法是自定义AuthenticationFilter,实现认证逻辑,认证通过,继续管道处理,认证失败,直接返回认证失败结果,类似如下:
publicasyncTaskAuthenticateAsync(HTTPAuthenticationContextcontext,CancellationTokencancellationToken)
{
varprincipal=awaitthis.AuthenticateAsync(context.Request);
if(principal==null)
{
context.Request.Headers.GetCookies().Clear();
context.ErrorResult=newAuthenticationFailuResult("未授权请求",context.Request);
}
else
{
context.Principal=principal;
}
}
但在.netco中,AuthenticationFilter已经不复存在,取而代之的是认证中间件。至于理由,我想应该是微软觉得Authentication并非业务紧密相关的,放在管道中间件中更合适。那么,话说回来,在.netco中,我们应该怎么实现认证呢?如大家所愿,微软已经为我们提供了认证中间件。这里以CookieAuthenticationMiddlewa中间件为例,来介绍认证的实现。
1、引用Microsoft.AspNetCo.Authentication.Cookies包。项目实践中引用的是"Microsoft.AspNetCo.Authentication.Cookies":"1.1.0"。
2、Startup中注册及配置认证、授权服务:
服务注册:
services.AddMvc(options=
{
//添加模型绑定过滤器
options.Filters.Add(typeof(ModelValidateActionFilter));
//添加授权过滤器,以便强制执行Authentication跳转及屏蔽逻辑
//varpolicy=newAuthorizationPolicyBuilder().RequiAuthenticatedUser().Build();
varpolicy=newAuthorizationPolicyBuilder().AddRequiments(newAuthenticationRequiment()).Build();
options.Filters.Add(newAuthorizeFilter(policy));
});
//services.AddAuthorization(options=
//{
//options.AddPolicy("RequiAuthentication",policy=policy.AddRequiments(newAuthenticationRequiment()));
//});
大家注意,上面代码中有两处注释掉的地方。第一处注释,RequiAuthenticatedUser()是.netco预定义的授权验证,代表通过授权验证的最低要求是提供经过认证的Identity。Demo中,我的要求也是这个,只要是经过基本认证的用户即可,那为什么Demo中没有使用呢?因为这里是个坑!实际实践中,我发现,采用注释中的做法,无论如何,调用总是返回,迫不得已,download认证及授权源码,发现该处逻辑是这样的:
varuser=context.User;
varuserIsAnonymous=
user?.Identity==null
!user.Identities.Any(i=i.IsAuthenticated);
if(!userIsAnonymous)
{
context.Succeed(quiment);
}
加入断点猛调,发现IsAuthenticated永远是false!!!迫不得已,反编译查看源码,发现ClaimsIdentity的IsAuthenticated属性是这样定义的:
WTF!!!坑爹么这是!!!.netframework中,记得这里的逻辑是,只要Name非空,就返回true,到了.netco中成了这样,你说坑不坑。。。
那怎么办?总不能放弃吧?我想,大家第一想法应该是继承ClaimsIdentity自定义一个Identity,尤其是看到属性上那个virtual的时候,我也不例外。可继承后,发现认证框架那儿依然不认,还是一直返回false,可能是我哪里用的不对吧。所以,Startup中第一处注释出现了。最终解决方案是自定义AuthenticationRequiment及处理器,实现要求的验证,如下:
publicclassAuthenticationRequiment:AuthorizationHandlerAuthenticationRequiment,IAuthorizationRequiment
{
protectedoverrideTaskHandleRequimentAsync(AuthorizationHandlerContextcontext,AuthenticationRequimentquiment)
{
varuser=context.User;
varuserIsAnonymous=
user?.Identity==null
string.IsNullOrWhiteSpace(user.Identity.Name);
if(!userIsAnonymous)
{
context.Succeed(quiment);
}
turnTaskCache.CompletedTask;
}
}
上述代码红色的部分便是相对默认实现变化的部分。
startup中第二部分注释,是注册授权策略的,注册方法也是北京哪家医院看白癜风最好哪些偏方能治疗白癜风