Почему моя ClaimsIdentity IsAuthenticated всегда неверна (для фильтра авторизации веб-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 и назначил его потоку?
Ответы
Ответ 1
Проблема заключается в том, что в .Net 4.5 произошел сбой. Как объясняется в этой статье, просто создание идентификатора претензии больше не делает его IsAuthenticated return true. Вместо этого вам нужно передать некоторую строку (неважно, что) в конструктор.
Итак, эта строка в приведенном выше коде:
var claimsIdentity = new ClaimsIdentity( claims );
Становится следующим:
// exact string doesn't matter
var claimsIdentity = new ClaimsIdentity( claims, "CustomApiKeyAuth" );
И проблема решена.
Я предполагаю, что этот Q & A в основном является повторением связанной статьи, но проблема была сложной для меня, поэтому я надеюсь, что добавив это, я сделаю ее более доступной для Google в будущем.
Ответ 2
Хотя предоставленный ответ имеет некоторую юридическую силу, он не совсем корректен. Вы не можете предположить, что просто добавление любой строки будет волшебным образом работать. Как указано в одном из комментариев, эта строка должна соответствовать одной из перечислений 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