Dans un projet d'API Web, je remplace le processus d'authentification normal pour vérifier les jetons à la place. Le code ressemble à ceci:
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;
}
Et puis plus tard, lorsque j'applique le [Authorize]
attribut à un contrôleur, il n'autorise pas.
Le code de débogage confirme le même comportement:
// ALWAYS FALSE!
if ( HttpContext.Current.User.Identity.IsAuthenticated ) {
// do something
}
Pourquoi pense-t-il que l'utilisateur n'est pas authentifié même si j'ai construit un ClaimsIdentity valide et que je l'ai affecté au thread?
Le problème est dû à un changement de rupture dans .Net 4.5. Comme expliqué par cet article , la simple construction d'une identité de revendications ne rend plus le retour IsAuthenticated vrai. Au lieu de cela, vous devez passer une chaîne (peu importe quoi) dans le constructeur.
Donc, cette ligne dans le code ci-dessus:
var claimsIdentity = new ClaimsIdentity( claims );
Devient ceci:
// exact string doesn't matter
var claimsIdentity = new ClaimsIdentity( claims, "CustomApiKeyAuth" );
Et le problème est résolu. Mise à jour: voir une autre réponse de Leo. La valeur exacte AuthenticationType peut ou non être importante selon ce que vous avez d'autre dans votre pipeline d'authentification.
Mise à jour 2: comme l'a suggéré Robin van der Knaap dans les commentaires, l'un des System.Security.Claims.AuthenticationTypes
les valeurs peuvent être appropriées.
var claimsIdentity = new ClaimsIdentity( claims, AuthenticationTypes.Password );
// and elsewhere in your application...
if (User.Identity.AuthenticationType == AuthenticationTypes.Password) {
// ...
}
Bien que la réponse fournie ait une certaine validité, elle n'est pas entièrement correcte. Vous ne pouvez pas supposer que l'ajout d'une chaîne fonctionnera comme par magie. Comme indiqué dans l'un des commentaires, cette chaîne doit correspondre à l'une des énumérations AuthenticationTypes
qui à son tour doit correspondre à celle spécifiée dans le middleware d'authentification/autorisation OWIN .... par exemple ...
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
});
}
Cependant, dans le scénario ci-dessus, cela n'aurait pas beaucoup d'importance. Mais, si vous utilisez plusieurs niveaux d'authentification/autorisation, les revendications seront associées à celle qui correspond au même AuthenticationType
... un autre exemple est lorsque vous utilisez l'authentification par cookie ...
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login")
});
}
où AuthenticationType
décrit le nom du cookie, car votre application peut avoir obtenu d'autres cookies d'autres fournisseurs, il est important que vous définissiez AuthenticationType
lors de l'instanciation des revendications afin de les associer ensuite à la bonne biscuit