52

W projekcie Web API zastępuję zwykły proces uwierzytelniania, aby zamiast tego sprawdzać tokeny. Kod wygląda mniej więcej tak:Dlaczego moje ClaimsIdentity IsAuthenticated zawsze są fałszywe (w przypadku filtra Web api Authorize)?

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

a potem, kiedy stosuje się atrybut [Authorize] do sterownika, to nie zezwalają.

debugowania kodu potwierdza ten sam problem:

// ALWAYS FALSE! 
if (HttpContext.Current.User.Identity.IsAuthenticated) { 
    // do something 
} 

Dlaczego uważasz, że użytkownik nie jest uwierzytelniony chociaż mam zbudowany poprawny ClaimsIdentity i przypisać go do wątku?

Odpowiedz

109

Problem jest spowodowany zerwaniem zmiany w .Net 4.5. Jak wyjaśnił this article, samo skonstruowanie tożsamości oświadczenia nie powoduje już, że IsAuthenticated zwraca true. Zamiast tego musisz przekazać jakiś ciąg (nieważne co) do konstruktora.

więc ta linia w powyższym kodzie:

var claimsIdentity = new ClaimsIdentity(claims); 

staje się w ten sposób:

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

A problem jest rozwiązany. Aktualizacja: zobacz inną odpowiedź od Leo. Dokładna wartość AuthenticationType może, ale nie musi być ważna, w zależności od tego, co jeszcze masz w potoku auth.

Aktualizacja 2: jak sugeruje Robin van der Knaap w komentarzach, jedna z wartości System.Security.Claims.AuthenticationTypes może być odpowiednia.

var claimsIdentity = new ClaimsIdentity(claims, AuthenticationTypes.Password); 

// and elsewhere in your application... 
if (User.Identity.AuthenticationType == AuthenticationTypes.Password) { 
    // ... 
} 
+8

Mimo że możesz dodać dowolny ciąg znaków, zgodnie z MSDN to zazwyczaj powinna być jedną z wartości zdefiniowanych w klasie AuthenticationTypes. http://msdn.microsoft.com/en-us/library/system.security.claims.claimsidentity.authenticationtype(vsv.110).aspx –

+1

Przykład: var claimsIdentity = new ClaimsIdentity (claim, AuthenticationTypes.Password); –

+2

Wartość ciągu staje się widoczna w User.Identity.AuthenticationType –

10

Chociaż dostarczona odpowiedź ma w sobie pewną wartość, nie jest całkowicie poprawna. Nie możesz zakładać, że samo dodanie dowolnego ciągu zadziała w magiczny sposób. Jak stwierdzono w jednym z komentarzem, ten ciąg musi odpowiadać jednej z AuthenticationTypes wyliczenia, które z kolei muszą być zgodne z jedną określoną w middleware uwierzytelniania OWIN/autoryzacji .... na przykład ...

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 
       });    
     } 

jednak w powyższym scenariuszu nie miałoby to większego znaczenia. Ale jeśli używasz więcej poziomów uwierzytelniania/autoryzacji roszczenia zostanie przypisana do jednego, który odpowiada sam AuthenticationType ... Innym przykładem jest podczas korzystania z uwierzytelniania ciasteczka ...

public void Configuration(IAppBuilder app) 
     { 
      app.UseCookieAuthentication(new CookieAuthenticationOptions 
      { 
       AuthenticationType = "ApplicationCookie", 
       LoginPath = new PathString("/auth/login") 
      }); 
     } 

gdzie AuthenticationType opisuje nazwę pliku cookie, ponieważ Twoja aplikacja mogła uzyskać inne pliki cookie od innych dostawców, ważne jest, aby ustawić AuthenticationType podczas tworzenia reklamacji w celu skojarzenia z prawidłowym plikiem cookie.

+0

W .NET Core możesz używać stałych jako 'AuthenticationType', np.[CookieAuthenticationDefaults.AuthenticationScheme] (https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.cookies.cookieauthenticationdefaults.authenticationscheme) lub [JwtBearerDefaults.AuthenticationScheme] (https://docs.microsoft .com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbearerdefaults.authenticationscheme). –