Введение в аутентификацию с помощью ASP.NET Core
Это первая статья из серии, посвященной проверке подлинности и авторизации в ASP.NET Core. В этом посте я расскажу об аутентификации в целом и о том, как работает аутентификация на основе утверждений в ASP.NET Core.
Разница между аутентификацией и авторизацией
Прежде всего, следует уточнить разницу между этими двумя зависимыми гранями безопасности. Простой ответ заключается в том, что аутентификация — это процесс определения того , кто вы есть , а авторизация вращается вокруг того, что вам разрешено делать , т. е. разрешений. Очевидно, прежде чем вы сможете определить, что разрешено делать пользователю, вам нужно знать, кто он такой, поэтому, когда требуется авторизация, вы также должны сначала каким-то образом аутентифицировать пользователя.
Аутентификация в ASP.NET Core
Фундаментальные свойства, связанные с идентификацией, в ASP.NET Core практически не изменились — хотя они и отличаются, они должны быть знакомы разработчикам ASP.NET в целом. Например, в ASP.NET 4.x есть свойство, называемое User
on HttpContext
, которое имеет тип IPrincipal
, представляющий текущего пользователя для запроса. В ASP.NET Core есть похожее свойство с именем User
, разница в том, что это свойство имеет тип ClaimsPrincipal
, который реализует IPrincipal
.
Переход к использованию ClaimsPrincipal
подчеркивает фундаментальный сдвиг в том, как работает проверка подлинности в ASP.NET Core по сравнению с ASP.NET 4.x. Ранее авторизация обычно основывалась на ролях, поэтому пользователь мог принадлежать к одной или нескольким ролям, а различные разделы вашего приложения могли требовать от пользователя наличия определенной роли для доступа к нему. В ASP.NET Core этот тип авторизации на основе ролей по-прежнему можно использовать, но в первую очередь из соображений обратной совместимости. Маршрут, который они действительно хотят, чтобы вы выбрали, — это аутентификация на основе утверждений .
Проверка подлинности на основе утверждений
Концепция проверки подлинности на основе утверждений может показаться немного запутанной, когда вы столкнетесь с ней впервые, но на практике она, вероятно, очень похожа на подходы, которые вы уже используете. Вы можете думать об утверждениях как об утверждении или свойстве конкретной идентичности. Этот оператор состоит из имени и значения. Например, у вас может быть DateOfBirth
претензия, FirstName
претензия, EmailAddress
претензия или IsVIP
претензия. Обратите внимание, что эти утверждения касаются того, что или кто представляет собой личность , а не того, что они могут сделать .
Само удостоверение представляет собой одно объявление, с которым может быть связано множество утверждений. Например, рассмотрим водительские права. Это единое удостоверение, которое содержит ряд утверждений — FirstName
, LastName
, DateOfBirth
и Address
какие транспортные средства вам разрешено водить. Ваш паспорт будет другим удостоверением личности с другим набором требований.
Итак, давайте посмотрим на это в контексте ASP.NET Core. Удостоверения в ASP.NET Core представляют собой файл ClaimsIdentity
. Упрощенная версия класса может выглядеть так (фактический класс намного больше!):
public class ClaimsIdentity: IIdentity
{
public string AuthenticationType { get; }
public bool IsAuthenticated { get; }
public IEnumerable<Claim> Claims { get; }
public Claim FindFirst(string type) { /*...*/ }
public Claim HasClaim(string type, string value) { /*...*/ }
}
В этом плане я показал основные свойства, включая те, Claims
которые состоят из всех утверждений, связанных с личностью. Существует ряд служебных методов для работы с Claims
, два из которых я показал здесь. Они полезны, когда вы приходите к авторизации и пытаетесь определить, есть ли у конкретной личности Claim
интересующие вас данные.
Свойство AuthenticationType
говорит само за себя. В нашем предыдущем практическом примере это может быть строка Passport
или DriversLicense
, но в ASP.NET это, скорее всего, будет Cookies
, Bearer
или Google
и т. д. Это просто метод, который использовался для аутентификации пользователя и определения утверждений, связанных с удостоверением. .
Наконец, свойство IsAuthenticated
указывает, аутентифицировано ли удостоверение или нет. Это может показаться излишним — как можно получить удостоверение с утверждениями, если оно не аутентифицировано? Одним из сценариев может быть то, что вы разрешаете гостевым пользователям находиться на вашем сайте, например, в корзине покупок. У вас по-прежнему есть удостоверение, связанное с пользователем, и с этим удостоверением могут быть связанные утверждения, но они не будут аутентифицированы. Это важное различие, о котором следует помнить.
В дополнение к этому, в ASP.NET Core, если вы создаете ClaimsIdentity
и предоставляете AuthenticationType
в конструкторе, IsAuthenticated
всегда будет true. Таким образом, у аутентифицированного пользователя всегда должен AuthenticationType
быть AuthenticationType
.
Несколько личностей
Надеюсь, к этому моменту у вас есть концептуальное представление об утверждениях и о том, как они соотносятся с удостоверениями. В начале этого раздела я сказал, что User
свойство on HttpContext
— это ClaimsPrincipal
, а не ClaimsIdentity
, поэтому давайте взглянем на его упрощенную версию:
public class ClaimsPrincipal :IPrincipal
{
public IIdentity Identity { get; }
public IEnumerable<ClaimsIdentity> Identities { get; }
public IEnumerable<Claim> Claims { get; }
public bool IsInRole(string role) { /*...*/ }
public Claim FindFirst(string type) { /*...*/ }
public Claim HasClaim(string type, string value) { /*...*/ }
}
Важным моментом, который следует вынести из этого класса, является то, что есть Identities
свойство, которое возвращает IEnumerable<ClaimsIdentity>
. Таким образом, один ClaimsPrincipal
может состоять из нескольких Identities
. Также есть Identity
свойство, которое существует для реализации IPrincipal
интерфейса — в .NET Core оно просто выбирает первое удостоверение в Identities
.
Возвращаясь к нашему предыдущему примеру с паспортом и водительскими правами, множественные удостоверения личности действительно имеют смысл — эти документы являются формами удостоверения личности, каждый из которых содержит ряд утверждений. В этом случае вы являетесь принципалом, и у вас есть две формы идентичности. Когда у вас есть эти две части идентичности, вы, как принципал, наследуете все претензии от всех ваших идентичностей.
Рассмотрим другой практический пример — вы летите. Сначала вас попросят на стойке бронирования подтвердить утверждения, которые вы делаете о своих FirstName
и LastName
т. д. К счастью, вы вспомнили свой паспорт, который является удостоверением личности, подтверждающим эти утверждения, поэтому вы получаете свой посадочный талон и направляетесь в следующий шаг.
В службе безопасности вас попросят доказать утверждение, что вы забронировали билет на рейс. На этот раз вам понадобится другое удостоверение личности, которое вы носите с собой, посадочный талон, в котором есть FlightNumber
заявка, чтобы вы могли продолжить свой путь.
Наконец, как только вы пройдете проверку безопасности, вы доберетесь до VIP-зала, и вас попросят подтвердить ваш VIP-статус с помощью VIP Number
заявки. Это может быть VIP-карта, которая будет еще одной формой удостоверения личности и подтвердит запрошенное заявление. Если бы у вас не было карты, вы не могли бы предъявить запрошенное требование, вам бы отказали в доступе, и поэтому вас бы попросили уйти и прекратить скандалить.
Опять же, ключевыми моментами здесь являются то, что принципал может иметь несколько удостоверений, эти удостоверения могут иметь несколько утверждений, и ClaimsPrincipal
наследует все утверждения своего Identities
.
Как упоминалось ранее, авторизация на основе ролей в основном используется по соображениям обратной совместимости, поэтому этот метод IsInRole
, как правило, не нужен, если вы придерживаетесь аутентификации на основе утверждений, которая подчеркивается в ASP.NET Core. Под капотом это также просто реализовано с использованием утверждений, где тип утверждения по умолчанию равен RoleClaimType
, или ClaimType.Role
.
Снова думая с точки зрения ASP.NET Core, можно использовать несколько удостоверений и утверждений для защиты различных частей вашего приложения, как это было в аэропорту. Например, вы можете войти в систему с именем пользователя и паролем и получить набор утверждений на основе связанной с ним личности, которая позволяет вам просматривать сайт. Но скажем, у вас есть особенно важный раздел в вашем приложении, который вы хотите дополнительно обезопасить. Для этого может потребоваться, чтобы вы предоставили дополнительное удостоверение личности с дополнительными соответствующими утверждениями, например, с помощью двухфакторной аутентификации или повторного ввода пароля. Это позволило бы текущему принципу иметь несколько идентичностей и принять на себя требования всех предоставленных идентичностей.
Создание нового принципала
Итак, теперь мы увидели, как принципалы работают в ASP.NET Core. Как нам их создать? Простой пример, который вы можете увидеть при обычном входе на веб-страницу, может содержать код, подобный следующему.
public async Task<IActionResult> Login(string returnUrl = null)
{
const string Issuer = "https://gov.uk";
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, "Andrew", ClaimValueTypes.String, Issuer),
new Claim(ClaimTypes.Surname, "Lock", ClaimValueTypes.String, Issuer),
new Claim(ClaimTypes.Country, "UK", ClaimValueTypes.String, Issuer),
new Claim("ChildhoodHero", "Ronnie James Dio", ClaimValueTypes.String)
};
var userIdentity = new ClaimsIdentity(claims, "Passport");
var userPrincipal = new ClaimsPrincipal(userIdentity);
await HttpContext.Authentication.SignInAsync("Cookie", userPrincipal,
new AuthenticationProperties
{
ExpiresUtc = DateTime.UtcNow.AddMinutes(20),
IsPersistent = false,
AllowRefresh = false
});
return RedirectToLocal(returnUrl);
}
Этот метод в настоящее время жестко кодирует утверждения, но, очевидно, вы будете получать значения утверждений из базы данных или какого-либо другого источника. Первое, что мы делаем, — это создаем список утверждений, заполняя каждое из них строкой имени, строкой значения и необязательными полями Issuer
и . ClaimValueType
Класс ClaimType
является помощником, который предоставляет ряд общих типов утверждений. Например, каждый из них является URL-адресом http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
, но вам не обязательно использовать URL-адрес, как показано в последнем добавленном утверждении.
После того, как вы создали свои утверждения, вы можете создать новый ClaimsIdentity
, передав свой список утверждений и указав AuthenticationType
(чтобы убедиться, что ваша личность имеет IsAuthenticated=true
). Наконец, вы можете создать новый, ClaimsPrincipal
используя свою личность, и войти в систему пользователя. В этом случае мы говорим AuthenticationManager
использовать "Cookie"
обработчик аутентификации, который мы должны были настроить как часть нашего конвейера промежуточного программного обеспечения.
Резюме
В этом посте я описал, как работает проверка подлинности на основе утверждений и как она применяется к ASP.NET Core. В следующем посте я рассмотрю следующий этап процесса аутентификации — как на самом деле промежуточное ПО cookie выполняет вход с предоставленным принципалом. В последующих сообщениях будет рассказано, как вы можете использовать несколько обработчиков проверки подлинности, как работает авторизация и как ASP.NET Core Identity связывает все это вместе.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.