为什么我的ClaimsIdentity IsAuthenticated始终为false(对于web api授权过滤器)?

时间:2013-11-27 23:03:01

标签: c# asp.net asp.net-web-api claims-based-identity asp.net-4.5

在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并将其分配给线程,它仍然认为用户未经过身份验证?

2 个答案:

答案 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