在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