在Web API项目中,我重写了正常的身份验证过程来检查令牌。代码看起来像这样:
if ( true ) // validate the token or whatever here
{
var claims = new List<Claim>();
claims.Add( new Claim( ClaimTypes.Name, "MyUser" ) );
claims.Add( new Claim( ClaimTypes.NameIdentifier, "MyUserID" ) );
claims.Add( new Claim( ClaimTypes.Role, "MyRole" ) );
var claimsIdentity = new ClaimsIdentity( claims );
var principal = new ClaimsPrincipal( new[] { claimsIdentity } );
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;
}
然后,当我将[Authorize]
属性应用于控制器时,它无法授权。
调试代码确认了相同的行为:
// ALWAYS FALSE!
if ( HttpContext.Current.User.Identity.IsAuthenticated ) {
// do something
}
为什么即使我构建了有效的ClaimsIdentity并将其分配给线程,它仍然认为用户未经过身份验证?
答案 0 :(得分:118)
问题在于.Net 4.5的突破性变化。正如this article所解释的那样,简单地构建声明标识不再使其IsAuthenticated返回true。相反,您需要将一些字符串(无关紧要)传递给构造函数。
以上代码中的这一行:
var claimsIdentity = new ClaimsIdentity( claims );
成为这个:
// exact string doesn't matter
var claimsIdentity = new ClaimsIdentity( claims, "CustomApiKeyAuth" );
问题解决了。 更新:请参阅Leo的其他答案。确切的AuthenticationType值可能重要,也可能不重要,具体取决于您在auth管道中的其他内容。
更新2:正如Robin van der Knaap在评论中所建议的那样,其中一个System.Security.Claims.AuthenticationTypes
值可能是合适的。
var claimsIdentity = new ClaimsIdentity( claims, AuthenticationTypes.Password );
// and elsewhere in your application...
if (User.Identity.AuthenticationType == AuthenticationTypes.Password) {
// ...
}
答案 1 :(得分:11)
虽然提供的答案在其中有一定的效力,但它并不完全正确。你不能假设只是添加任何字符串将神奇地工作。正如其中一条评论中所述,此字符串必须与AuthenticationTypes
枚举中的一个匹配,后者必须与OWIN身份验证/授权中间件中指定的枚举匹配....例如...
public void ConfigureOAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
OAuthAuthorizationServerOptions serverOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new Microsoft.Owin.PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
AuthenticationType = AuthenticationTypes.Password,
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
Provider = new AppAuthServerProvider()
};
app.UseOAuthAuthorizationServer(serverOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = AuthenticationTypes.Password
});
}
然而,在上述情况下,它并不重要。但是,如果您使用更多身份验证/授权级别,则声明将与匹配相同AuthenticationType
的声明关联...另一个示例是您使用Cookie身份验证时...
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login")
});
}
其中AuthenticationType
描述了Cookie的名称,因为您的应用可能已经从其他提供商那里获得了其他Cookie,因此在实例化声明时设置AuthenticationType
以便将其关联到正确的cookie