Почему мой ClaimsIdentity IsAuthenticated всегда имеет значение false (для фильтра авторизации веб-API)?

В проекте веб-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 и назначил его потоку?


person explunit    schedule 27.11.2013    source источник


Ответы (2)


Проблема заключается в критическом изменении в .Net 4.5. Как поясняется в этой статье, простое построение удостоверения утверждения больше не приводит к тому, что IsAuthenticated возвращает значение true. Вместо этого вам нужно передать в конструктор некоторую строку (неважно какую).

Итак, эта строка в приведенном выше коде:

var claimsIdentity = new ClaimsIdentity( claims );

Становится это:

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

И проблема решена. Обновление: см. другой ответ от Лео. Точное значение AuthenticationType может быть важным или не иметь значения в зависимости от того, что еще у вас есть в конвейере аутентификации.

Обновление 2: как было предложено Робином ван дер Кнаапом в комментариях, одно из значений System.Security.Claims.AuthenticationTypes может быть подходящим.

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

// and elsewhere in your application...
if (User.Identity.AuthenticationType == AuthenticationTypes.Password) {
    // ...
}
person explunit    schedule 27.11.2013
comment
Хотя вы можете добавить любую строку, согласно MSDN это обычно должно быть одно из значений, определенных в классе AuthenticationTypes. msdn.microsoft .com / ru-ru / library / - person Robin van der Knaap; 14.02.2014
comment
Пример: var argumentsIdentity = new ClaimsIdentity (Claims, AuthenticationTypes.Password); - person Robin van der Knaap; 14.02.2014
comment
Значение строки становится видимым в User.Identity.AuthenticationType. - person Robin van der Knaap; 14.02.2014
comment
Вау, это действительно непонятно! Спасибо, что поделились этим здесь! Я застрял больше часа. - person DavidEdwards; 10.04.2015

Хотя предоставленный ответ имеет некоторую обоснованность, он не совсем правильный. Вы не можете предположить, что простое добавление какой-либо строки сработает волшебным образом. Как указано в одном из комментариев, эта строка должна соответствовать одному из _ 1_, которое, в свою очередь, должно соответствовать указанному в промежуточном программном обеспечении аутентификации / авторизации 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
                });            
        }

Однако в приведенном выше сценарии это не имело бы большого значения. Но если вы используете больше уровней аутентификации / авторизации, утверждения будут связаны с тем, который соответствует тому же _3 _... другой пример - когда вы используете аутентификацию cookie ...

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

где AuthenticationType описывает имя файла cookie, поскольку ваше приложение могло получать другие файлы cookie от других поставщиков, важно, чтобы вы установили AuthenticationType при создании экземпляра требований, чтобы затем связать его с правильным файлом cookie.

person Leo    schedule 25.05.2015
comment
В .NET Core вы можете использовать константы как AuthenticationType, например. CookieAuthenticationDefaults.AuthenticationScheme или JwtBearerDefaults.AuthenticationScheme. - person Alex Klaus; 28.02.2018
comment
Обратите внимание: при создании ClaimsIdentity вам необходимо передать имя схемы как AuthenticationType (например, new ClaimsIdentity(claims, AuthenticationScheme)). В противном случае флаг IsAuthenticated на личности будет false. Я дважды сталкивался с одной и той же неинтуитивной проблемой за последние 2 года, и этот ответ снова помог мне. К сожалению, я не могу проголосовать за этот ответ дважды. - person Alex Klaus; 19.08.2019