为什么我的声明身份经过身份验证总是假的(对于 Web API 授权过滤器)



在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
}

为什么它认为用户没有经过身份验证,即使我已经构造了一个有效的 ClaimIdentity 并将其分配给线程?

该问题是由于 .Net 4.5 中的重大更改。如本文所述,仅构造声明标识不再使其返回 IsAuthenticated 返回 true。相反,您需要将一些字符串(无关紧要(传递到构造函数中。

所以上面代码中的这一行:

var claimsIdentity = new ClaimsIdentity( claims );

变成这样:

// exact string doesn't matter
var claimsIdentity = new ClaimsIdentity( claims, "CustomApiKeyAuth" );

问题解决了。更新:请参阅狮子座的其他答案。确切的 AuthenticationType 值可能很重要,也可能不重要,具体取决于身份验证管道中的其他内容。

更新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) {
    // ...
}

虽然提供的答案有一定的道理,但它并不完全正确。你不能假设只添加任何字符串就会神奇地工作。如其中一个注释中所述,此字符串必须与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

相关内容

最新更新