Форум программистов, компьютерный форум, киберфорум
C#: ASP.NET Core
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
0 / 0 / 1
Регистрация: 31.08.2021
Сообщений: 30
.NET 7

Как присоединить ClaimsPrincipal к JWT токену?

02.07.2023, 12:04. Показов 1214. Ответов 11

Студворк — интернет-сервис помощи студентам
Всем читающим доброго времени суток. Я изучаю ASP.NET Core по интернет-руководству "Руководство по ASP.NET Core 7" (https://metanit.com/sharp/aspnet6/) и остановился на аутентификации и авторизации (глава 13) с помощью ClaimPrincipal и ClaimsIdentity (https://metanit.com/sharp/aspnet6/13.5.php). В руководстве простенький пример с созданием юзера (ClaimsPrincipal) с одним удостоверением (ClaimsIdentity). Этот юзер отправляется клиенту вместе с аутентификационным Cookies (вызов "context.SignInAsync(claimsPrincipal )"). Т. е. схема простая - при всех последующих запросах, сервер, получая от клиента ранее отправленный Cookies, сможет достать из него объект ClaimsPrincipal, по которому он сможет понять, что за пользователь сделал запрос и какие у него права. Отсюда вопрос: можно ли отправить этого пользователя (ClaimsPrincipal) не с Cookies, а с JWT токеном и если да, то как? В сети инфы об этом не нашел, хотя в руководстве написано, что ClaimsPrincipal можно получить и из JWT токена (значит и отправить с ним тоже, да?). Конечно, я допускаю, что автор руководства не вникнул и написал фигню, но написанное им мне кажется логичным. Всем заранее спасибо.

Вот код из руководства:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
 
var builder = WebApplication.CreateBuilder();
 
// аутентификация с помощью куки
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();
 
var app = builder.Build();
 
app.UseAuthentication();
 
app.MapGet("/login", async (HttpContext context) =>
{
    var claimsIdentity = new ClaimsIdentity("Undefined");
    var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
    // установка аутентификационных куки
    await context.SignInAsync(claimsPrincipal);
    return Results.Redirect("/");
});
 
app.MapGet("/logout", async (HttpContext context) =>
{
    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    return "Данные удалены";
});
app.Map("/", (HttpContext context) =>
{
    var user = context.User.Identity;
    if (user is not null && user.IsAuthenticated)
    {
        return $"Пользователь аутентифицирован. Тип аутентификации: {user.AuthenticationType}";
    }
    else
    {
        return "Пользователь НЕ аутентифицирован";
    }
});
 
app.Run();
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
02.07.2023, 12:04
Ответы с готовыми решениями:

Как переделать контроллер с sequelize под обычные запросы с jwt токеном
Делаю курсовую работу, сделал весь бек и сказали, что нельзя юзать никакие ОРМ и ничего такого, пытался сделать через запросы контроллер...

Авторизация по токену Vk
StatusSet(); setInterval(function(){StatusSet()},5000); log("Start",getDate()); vk.default_callback = function(a){}; ...

Авторизация по токену
Добрый день! Помогите, пожалуйста. У меня есть два проекта. Первый это приложение MVC, а второй небольшой API. В первом...

11
403 / 265 / 69
Регистрация: 12.04.2020
Сообщений: 1,404
02.07.2023, 12:27
Цитата Сообщение от One290 Посмотреть сообщение
ClaimsPrincipal можно получить и из JWT токена (значит и отправить с ним тоже, да?)
можно отправить
но получать смысл?
роли и так можно отправить, вроде никакой не секрет это
0
0 / 0 / 1
Регистрация: 31.08.2021
Сообщений: 30
02.07.2023, 12:56  [ТС]
Это, конечно, не совсем то, что мне нужно, но хоть что-то. Ну и как их отправить? Насколько я сейчас знаю, роли это ClaimsIdentity.DefaultRoleClaimType. Т. е. чтобы отправить роль с JWT токеном, нужно "присоединить" к нему ClaimsIdentity, а в параметрах конструктора JwtSecurityToken имеется, максимум, параметр "claims" типа "IEnumerable<Claim>". Можешь ответить подробнее (желательно хотя бы с мини-кодом)?

Вот как я формировал JWT токен:

C#
1
2
3
4
5
6
List<Claim> claims = new List<Claim> { new Claim(ClaimTypes.Name, "Amogus") };
JwtSecurityToken jwt = new JwtSecurityToken(issuer: AuthenticationOptions.ISSUER, audience: AuthenticationOptions.AUDIENCE, claims: claims, expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(2)), signingCredentials: new SigningCredentials(AuthenticationOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));
string encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
var response = new { access_token = encodedJwt, username = "Amogus" };
//context.SignInAsync(ClaimsPrincipal);// А вот так бы я отправил куки с пользователем внутри
return Results.Json(response);
0
HF
 Аватар для HF
1303 / 882 / 199
Регистрация: 09.09.2011
Сообщений: 2,590
Записей в блоге: 2
02.07.2023, 14:10
Лучший ответ Сообщение было отмечено One290 как решение

Решение

Цитата Сообщение от One290 Посмотреть сообщение
сможет достать из него объект ClaimsPrincipal
ClaimsPrincipal - контейнер для одного/много ClaimsIdentity. Которые могут быть разного типа - например ClaimsIdentity или WindowsIdentity.
Его нельзя отправить, так как "удостоверением на входе" является Identity, которое вы предоставляете для доступа. А уже "карточкой доступа по территории закрытого объекта" является ClaimsPrincipal.

Цитата Сообщение от One290 Посмотреть сообщение
роли это ClaimsIdentity.DefaultRoleClaimType
Надеюсь что не ошибаюсь, если скажу что - Нет, это не роли, это идентификатор по которому будут считываться роли из коллекции claims. Например, вы можете создать токен Другого типа и назначить для ролей совсем другую коллекцию. Ну например назовём её "Permission". И тогда при использовании метода HasRole, "под капотом" будут читаться claims не с типом "Role" а с типом "Permission".

Цитата Сообщение от One290 Посмотреть сообщение
можно ли отправить этого пользователя (ClaimsPrincipal) не с Cookies, а с JWT токеном и если да, то как?
Т. е. схема простая - при всех последующих запросах, сервер, получая от клиента ранее отправленный Cookies, сможет достать из него объект ClaimsPrincipal, по которому он сможет понять, что за пользователь сделал запрос и какие у него права.
До вопроса вы уже озвучили ответ. Как только JWT токен прошёл валидацию - он сразу стал ClaimsIdentity для ClaimsPrincipal. Он же собственно и стал этим HttpContext.User.Identity. Если у вас там есть полезные данные - используйте их.

Уже позже, во время написания текста, я видимо понял причину вопроса. Вам надо использовать JwtBearerDefaults.AuthenticationScheme вместо CookieAuthenticationDefaults.Authenticat ionScheme. То есть поставить официальное расширение Microsoft.AspNetCore.Authentication.JwtB earer и настроить опции валидации. Тогда все входящие токены будут автоматически транслироваться в Identity.
Ссылка: "Авторизация с помощью JWT-токенов"

Есть другой вариант - продолжение вашего. Как идентифицировать по JWT токену, но использовать Cookie схему. Тут тоже есть два варианта: автоматический и ручной.

Автоматический - ссылка выше. Опции валидации и идентификации, автоматически транслируют токен.
Ручной - все ваши методы не имеют атрибута [Authorize], но первым что вы там делаете
- достаёте из известного источника (заголовки, куки, строка запроса...) токен, распаковыете его и валидируете.
- После валидации можно или вернуть ошибку валидации или продолжать действие контроллера
- после успешной валидации, имеете доступ до данных в токене и используете их для работы (например, имя, роли, е-мейл, другие записи).

Добавлено через 38 минут
Походу я не дописал ещё, для лучшего понимания процесса.
Вот этот вариант из примера
C#
1
app.MapGet("/login", async (HttpContext context) => ...
и есть точка входа где вы должны сделать Это. В вашем случае - в этом методе ищете, распаковываете, валидируете JWT. С этими данными создаёте ClaimsIdentity и делаете SignIn. То есть аналог замены JwtBearer пакета.
1
0 / 0 / 1
Регистрация: 31.08.2021
Сообщений: 30
03.07.2023, 08:02  [ТС]
HF, В общем, я пришел к такому выводу (не знаю насколько он верный): раз вместе с JWT-токенами можно отправлять только отдельные ClaimsIdentity, то для формирования полноценного ClaimsPrincipal с несколькими ClaimsIdentity, я буду отправлять несколько JWT-токенов (каждый из которых будет "нести в себе" свой ClaimsIdentity). Это, конечно, не очень хорошо смотрится в сравнении с одним Cookies, хранящим весь ClaimsPrincipal целиком, но других вариантов я не вижу. Всем спасибо (вернее, только тебе, HF).
0
HF
 Аватар для HF
1303 / 882 / 199
Регистрация: 09.09.2011
Сообщений: 2,590
Записей в блоге: 2
03.07.2023, 11:24
Цитата Сообщение от One290 Посмотреть сообщение
я буду отправлять несколько JWT-токенов (каждый из которых будет "нести в себе" свой ClaimsIdentity)
Не совсем понятна ситуация в которой необходимо это таскать. Грубо говоря - токен = пользователь. Несколько токенов = ... эмм.. что там?
И в начале задачи не было ничего рассказано про такую активность в ClaimsPrincipal. Уверены что правильно поняли этот функционал или что не "переборщили" с данными?
1
0 / 0 / 1
Регистрация: 31.08.2021
Сообщений: 30
12.07.2023, 11:43  [ТС]
HF, В моем понимании, ClaimsPrincipal это и есть пользователь, а ClaimsIdentity это его "пропуски". Возьмем, к примеру, тюрьму - пусть у нас будут "обычные" охранники с одним пропуском только в тот блок, который они охраняют, "супер" охранники с двумя пропусками в два разных блока, соответственно, и надзиратели, имеющие, пропуски во все блоки. Охранники и надзиратели - ClaimsPrincipal, их пропуска - ClaimsIdentity.

JWT-токены, соответственно, и будут этими пропусками, а клиент - охранником
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,227
12.07.2023, 12:12
Цитата Сообщение от One290 Посмотреть сообщение
ClaimsPrincipal
Переводите слово, Principal - это владелец прав и claims-ов. Некая абстракция, обладающая правами и свойствами.
А Identity - это уже сущность (пользователь), который характеризуется этими свойствами (claims-ами).
То есть Identity является частью Principal (через композицию).
1
HF
 Аватар для HF
1303 / 882 / 199
Регистрация: 09.09.2011
Сообщений: 2,590
Записей в блоге: 2
12.07.2023, 12:57
Цитата Сообщение от One290 Посмотреть сообщение
В моем понимании, ClaimsPrincipal это и есть пользователь, а ClaimsIdentity это его "пропуски". Возьмем, к примеру, тюрьму - пусть у нас будут "обычные" охранники с одним пропуском только в тот блок, который они охраняют, "супер" охранники с двумя пропусками в два разных блока, соответственно, и надзиратели, имеющие, пропуски во все блоки. Охранники и надзиратели - ClaimsPrincipal, их пропуска - ClaimsIdentity.
JWT-токены, соответственно, и будут этими пропусками, а клиент - охранником
С примерами вы "намешали всё в кучу".
В случае "ClaimsPrincipal это и есть пользователь, а ClaimsIdentity это его "пропуски"" - пусть так, это близко к смыслу.
Но потом вы начали про охранников и это стало какой-то кашей.

Возьмём ваш пример. Пусть ClaimsPrincipal - пользователь, а ClaimsIdentity - его пропуски.
Вы зашли в здание и у вас куча пропусков? Это же лишено смысла в обычной жизни. Ведь обычно дают Один пропуск с супер-доступом, вместо 10 разных на каждую дверь.
И о каких охранниках-надзирателях речь, если вы сами сказали что ClaimsPrincipal - пользователь. Тогда должно быть ХХ ClaimsPrincipal.ов? Но у вас же один браузер, одно подключение. Вы там собираетесь за один вход затягивать всю базу пользователей? Сами то оцените этот сценарий.

Поэтому я считаю что вы просто ошибаетесь в замысле этих пропусков.
0
0 / 0 / 1
Регистрация: 31.08.2021
Сообщений: 30
14.07.2023, 10:40  [ТС]
HF, Просто мне не дает покоя тот факт, что у ClaimsPrincipal может быть множество ClaimsIdentity. Если следовать Вашей логике, то у ClaimsPrincipal должен быть один ClaimsIdentity (или класса ClaimsPrincipal вообще не должно существовать, а вместо него должен быть только один ClaimsIdentity). Раз разработчики класса ClaimsPrincipal его так реализовали, то ведь не просто так, верно? А раз что-то реализовано, значит надо этим пользоваться и не важно какой смысл в это будет вкладывать отдельно взятый программист. Не особо важен даже смысл, который вкладывали разработчики - важен только сам факт наличия функционала.

А насчет
Цитата Сообщение от HF Посмотреть сообщение
ХХ ClaimsPrincipal.ов
: относительно сервера так и есть - каждый клиент присылает свой ClaimsPrincipal. А у клиента в печенюхе хранится только его ClaimsPrincipal.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,227
14.07.2023, 11:36
Цитата Сообщение от One290 Посмотреть сообщение
Просто мне не дает покоя тот факт, что у ClaimsPrincipal может быть множество ClaimsIdentity.
Хорошее замечание, сам в это особо не вникал.
Первоначальный IPrincipal выглядил вот так: (собственно на основе этого я и рассуждал)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ClaimsPrincipal : IPrincipal {...}
 
public interface IPrincipal
    {
        // Retrieve the identity object
        IIdentity? Identity { get; } // всего один
 
        // Perform a check for a specific role
        bool IsInRole(string role);
    }
 
public interface IIdentity
    {
        // Access to the name string
        string? Name { get; }
 
        // Access to Authentication 'type' info
        string? AuthenticationType { get; }
 
        // Determine if this represents the unauthenticated identity
        bool IsAuthenticated { get; }
    }
Но на SO уже задавали такой же как и у вас вопрос:

The thing is, ClaimsPrincipal contains just a collection of identities and points to the currently used one but as far as I know, the principal usually never contains more than 1 identity and even if it would - the user is never logged in with 2 or more identities.
И в ответе:
Principal = User
Identity = Driver's License, Passport, Credit Card, Google Account, Facebook Account, RSA SecurID, Finger print, Facial recognition, etc.
Таки principal - это пользователь (абстракция обладающая правами и свойствами).
Identity - В машинном переводе пишут - "Удостоверение". Все равно, имхо, на русский язык как-то плохо ложится. Хотя смысл вроде бы отображает.
Аля, идентификационные данные или данные, удостоверяющие личность. Их стало больше одного, когда появилось N-факторная аутентификация.
In fact the ClaimsPrincipal in context will always have more than 1 identity if your application requires n factor authentication (n > 1).
Добавлено через 5 минут
И в коде ClaimsPrincipal как раз есть PrimaryIdentitySelector, указывающий на основные идентификационные данные.
1
HF
 Аватар для HF
1303 / 882 / 199
Регистрация: 09.09.2011
Сообщений: 2,590
Записей в блоге: 2
14.07.2023, 12:03
Цитата Сообщение от IamRain Посмотреть сообщение
Identity - В машинном переводе пишут - "Удостоверение". Все равно, имхо, на русский язык как-то плохо ложится. Хотя смысл вроде бы отображает.
Аля, идентификационные данные или данные, удостоверяющие личность. Их стало больше одного, когда появилось N-факторная аутентификация.
Блин, я когда предыдущее сообщение (post16971475) писал, расписал эту фишку, а потом подумал "Ну нафиг, не буду усложнять примерами" и.. стёр.
Раз всё-таки до этого дошло, вот ссылка на официальную доку: Authorize with a specific scheme in ASP.NET Core
Где показана настройка для "кучи" JWT.

Ещё раз уточню - изначально говорилось про "хранить множество ClaimsPrincipal". То есть ТСом подразумевалось хранение всех пользователей с их правами.
И, надеюсь, что мы выяснили, что это ошибочное представление про работу аутентификации?
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.07.2023, 12:03
Помогаю со студенческими работами здесь

Аутентификация и авторизация по токену
Всем привет! Есть 2 домена, на одном из которых пользователь может ввести логин и пароль и получить взамен строковый ключ (токен): 1 ключ...

Как присоединить систему 5.1 к ноутбуку?
В подарок досталась система Microlab X4 5.1, отказываться неудобно, да и как раз искал себе новые колонки )) Только вот проблемка такая...

Как присоединить GLUT к CODEBLOCKS
Пробовал двумя способами и не получается Первый через мастер CODEBLOCKS , указываем путь к папке с GLUT, запускаем проект, получаем такой...

Как присоединить вторую форму?
Вернее как соедить я знаю, просто из другого проекта как взять незнаю. Готовую уже хочу взять!

Как присоединить ДВД-привод
ASUS P8B75-V мат. плата и привод Optiarc DVD RW AD-5170A куда и какими проводами их сцепить? ))


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru