0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
||||||
Получение доступа с помощью cookies к защищённому api через oauth2.0 openid connect server. Клиенты asp.net core mvc, re20.07.2023, 23:06. Показов 1631. Ответов 23
Может кто делал сервер авторизации на asp net core с использованием openiddict, asp net core mvc с react js (в одном приложении и по отдельности), сервер ресурсов (защищённое api) и всё это работало через cookies? Сервер аутентификации - OpeniddictServer. Сервер ресурсов - ResourceServer. Пример тут с ангуляром, брал его за основу: https://github.com/damienbod/AspNetCoreOpeniddict (это не мой проект. Но я взял его за основу и переделываю). Вот так я настраивал клиента:
0
|
20.07.2023, 23:06 | |
Ответы с готовыми решениями:
23
Пользователь запретил получение данных о местоположении. ASP.NET Core MVC Google map api ASP.NET Mvc 4 Авторизация через Steam OpenId Client ASP.NET MVC + Angular и Server side ASP.NET WEB.API |
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 07:35 [ТС] | |
Сейчас работвет всё, помещая токены в заголовки. Такой вариант мне не подходит. Нужно, чтобы всё работало на cookies, пусть хранятся токены в них. Вопрос: Как переделать работу существующих проектов так, чтобы они работали, используя cookies, а не помещали токены в заголовки?
0
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 08:20 [ТС] | |
Usaga, конечно не весь. Я же ссылку в вопросе оставил на пример проекта, который я взял за основу. Там токены записываются в заголовки. Вот ссылка ещё раз: https://github.com/damienbod/AspNetCoreOpeniddict
Код, который в вопросе - это код для настройки клиента mvc(with react.js). Его тоже можно (и наверное даже нужно) дорабатывать.
0
|
![]() ![]() 13433 / 8964 / 1324
Регистрация: 21.01.2016
Сообщений: 33,651
|
|
21.07.2023, 08:44 | |
jekamaster, а полностью задача как звучит?
Просто я подобное настраивал и в более сложных сценариях. Но я токен руками не подкладываю в запросы к API в браузере. Со стороны клиента инициирую запрос на веб-сервер, тот выполняет Challenge по схеме OpenIdConnectDefaults.AuthenticationScheme , а инфраструктура Asp.Net (в лице библиотеки OpenIdConnect - стандартной, официальной) сама всё валидирует и куку выплёвывает. Я только дополняю этот процесс ручным созданием Principal, что требуется для хранения дополнительных вещей в куки.И всё. За основу, когда-то, я брал этот пример. Кажется. Посмотри его.
0
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 10:34 [ТС] | |
Usaga, я вот похожим образом настраивал клиента, как ты сбросил пример. В целом, мой код похож на клиенте. И так всё работает. НО, проблема в том, что я не могу получить доступ к серверу ресурсов после такой аутентификации.
На схемах нарисовано, как должно работать. oauth2-caseflow.png - это аналог последней (третьей) схемы на первой картинке.
0
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 11:13 [ТС] | |
Читаем спецификацию RFC 6749 секция 1.1: https://datatracker.ietf.org/d... ection-1.1 .
Цитирую: "resource server The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens." Перевод цитаты: "сервер ресурсов Сервер, на котором размещены защищенные ресурсы, способный принимать запросы к защищенным ресурсам и отвечать на них с использованием токенов доступа."
0
|
![]() ![]() 13433 / 8964 / 1324
Регистрация: 21.01.2016
Сообщений: 33,651
|
|
21.07.2023, 11:25 | |
jekamaster, я не об этом спросил. Я спросил что в твоей системе есть сервер ресурсов, как ты к нему обращаешься, как проявляется "не могу получить доступ". Мы вроде бы конструктивно общаемся, не нужно впадать в подобные вещи.
Добавлено через 59 секунд И тыкай по нику пользователя, к которому обращаешься (над аватаркой). Так пользователю будет уведомление прилетать, что его где-то упомянули.
0
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 11:41 [ТС] | |
Usaga, я настроил клиента вот так:
builder.Services.AddAuthentication(confi g => { config.DefaultScheme = CookieAuthenticationDefaults.Authenticat ionScheme; config.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationSche me; }) .AddCookie(CookieAuthenticationDefaults. AuthenticationScheme, options => { options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; options.ExpireTimeSpan = TimeSpan.FromSeconds(100); options.SlidingExpiration = true; }) .AddOpenIdConnect(OpenIdConnectDefaults. AuthenticationScheme, options => { options.Authority = "https://localhost:44395"; options.ClientId = "platform-net-6"; options.ClientSecret = "123456789"; options.ResponseType = "code"; options.CallbackPath = "/signin-oidc"; options.SaveTokens = true; options.UsePkce = true; options.AutomaticRefreshInterval = TimeSpan.FromMinutes(5); options.UseTokenLifetime = true; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("offline_access"); options.Scope.Add("api"); options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenVali dationParameters { ValidIssuer = $"https://localhost:44395", RequireExpirationTime = true, ValidateLifetime = true, }; }); Сервер авторизации настроен вот так: services.AddDatabaseDeveloperPageExcepti onFilter(); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbC ontext>() .AddDefaultTokenProviders() .AddDefaultUI() .AddTokenProvider<Fido2UserTwoFactorToke nProvider>("FIDO2"); services.Configure<Fido2Configuration>(C onfiguration.GetSection("fido2")); services.AddScoped<Fido2Store>(); services.AddDistributedMemoryCache(); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(2); options.Cookie.HttpOnly = true; options.Cookie.SameSite = SameSiteMode.None; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; }); services.Configure<IdentityOptions>(opti ons => { // Configure Identity to use the same JWT claims as OpenIddict instead // of the legacy WS-Federation claims it uses by default (ClaimTypes), // which saves you from doing the mapping in your authorization controller. options.ClaimsIdentity.UserNameClaimType = Claims.Name; options.ClaimsIdentity.UserIdClaimType = Claims.Subject; options.ClaimsIdentity.RoleClaimType = Claims.Role; options.ClaimsIdentity.EmailClaimType = Claims.Email; // Note: to require account confirmation before login, // register an email sender service (IEmailSender) and // set options.SignIn.RequireConfirmedAccount to true. // // For more information, visit https://aka.ms/aspaccountconf. options.SignIn.RequireConfirmedAccount = false; }); // OpenIddict offers native integration with Quartz.NET to perform scheduled tasks // (like pruning orphaned authorizations/tokens from the database) at regular intervals. services.AddQuartz(options => { options.UseMicrosoftDependencyInjectionJ obFactory(); options.UseSimpleTypeLoader(); options.UseInMemoryStore(); }); services.AddCors(options => { options.AddPolicy("AllowAllOrigins", builder => { builder .AllowCredentials() .WithOrigins( "https://localhost:4200", "https://localhost:4204", "https://localhost:7082") .SetIsOriginAllowedToAllowWildcardSubdom ains() .AllowAnyHeader() .AllowAnyMethod(); }); }); // Register the Quartz.NET service and configure it to block shutdown until jobs are complete. services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true); services.AddAuthentication(CookieAuthent icationDefaults.AuthenticationScheme) .AddOpenIdConnect("KeyCloak", "KeyCloak", options => { options.SignInScheme = "Identity.External"; //Keycloak server options.Authority = Configuration.GetSection("Keycloak")["ServerRealm"]; //Keycloak client ID options.ClientId = Configuration.GetSection("Keycloak")["ClientId"]; //Keycloak client secret in user secrets for dev options.ClientSecret = Configuration.GetSection("Keycloak")["ClientSecret"]; //Keycloak .wellknown config origin to fetch config options.MetadataAddress = Configuration.GetSection("Keycloak")["Metadata"]; //Require keycloak to use SSL options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("openid"); options.Scope.Add("profile"); options.SaveTokens = true; options.ResponseType = OpenIdConnectResponseType.Code; options.RequireHttpsMetadata = false; //dev options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = ClaimTypes.Role, ValidateIssuer = true }; }); services.AddOpenIddict() .AddCore(options => { options.UseEntityFrameworkCore() .UseDbContext<ApplicationDbContext>(); options.UseQuartz(); }) .AddServer(options => { // Enable the authorization, logout, token and userinfo endpoints. options.SetAuthorizationEndpointUris("co nnect/authorize") //.SetDeviceEndpointUris("connect/device") .SetIntrospectionEndpointUris("connect/introspect") .SetLogoutEndpointUris("connect/logout") .SetTokenEndpointUris("connect/token") .SetUserinfoEndpointUris("connect/userinfo") .SetVerificationEndpointUris("connect/verify"); options.AllowAuthorizationCodeFlow() .AllowHybridFlow() .AllowClientCredentialsFlow() .AllowRefreshTokenFlow(); options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, "dataEventRecords", "api"); options.AddDevelopmentEncryptionCertific ate() .AddDevelopmentSigningCertificate(); options.UseAspNetCore() .EnableAuthorizationEndpointPassthrough( ) .EnableLogoutEndpointPassthrough() .EnableTokenEndpointPassthrough() .EnableUserinfoEndpointPassthrough() .EnableStatusCodePagesIntegration(); }) .AddValidation(options => { options.UseLocalServer(); options.UseAspNetCore(); }); services.AddHostedService<Worker>(); Это в "Worker" сервера авторизации: if (await manager.FindByClientIdAsync("platform-net-6") is null) { await manager.CreateAsync(new OpenIddictApplicationDescriptor { ClientId = "platform-net-6", ClientSecret = "123456789", DisplayName = "platform-net-6", ConsentType = ConsentTypes.Explicit, //Type = ClientTypes.Public RedirectUris = { new Uri("https://192.168.41.59:7082/signin-oidc"), new Uri("https://localhost:7082/signin-oidc"), new Uri("https://localhost:7094/signin-oidc") }, Permissions = { Permissions.Endpoints.Authorization, Permissions.Endpoints.Logout, Permissions.Endpoints.Token, Permissions.Endpoints.Revocation, Permissions.GrantTypes.AuthorizationCode , Permissions.GrantTypes.ClientCredentials , Permissions.GrantTypes.RefreshToken, Permissions.ResponseTypes.Code, Permissions.Scopes.Email, Permissions.Scopes.Profile, Permissions.Scopes.Roles, Permissions.Prefixes.Scope + "api" }, Requirements = { Requirements.Features.ProofKeyForCodeExc hange } }); ; } Сервер ресурсов настроен вот так: var connection = Configuration.GetConnectionString("Defau ltConnection"); services.AddDbContext<DataEventRecordCon text>(options => options.UseSqlite(connection) ); services.AddCors(options => { options.AddPolicy("AllowAllOrigins", builder => { builder .AllowCredentials() .WithOrigins( "https://localhost:4200", "https://localhost:7082") .SetIsOriginAllowedToAllowWildcardSubdom ains() .AllowAnyHeader() .AllowAnyMethod(); }); }); var guestPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .RequireClaim("scope", "dataEventRecords") .Build(); services.AddAuthentication(options => { options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.A uthenticationScheme; }); // Register the OpenIddict validation components. services.AddOpenIddict() .AddValidation(options => { // Note: the validation handler uses OpenID Connect discovery // to retrieve the address of the introspection endpoint. options.SetIssuer("https://localhost:44395/"); options.AddAudiences("rs_dataEventRecord sApi"); // Configure the validation handler to use introspection and register the client // credentials used when communicating with the remote introspection endpoint. options.UseIntrospection() .SetClientId("rs_dataEventRecordsApi") .SetClientSecret("dataEventRecordsSecret "); // Register the System.Net.Http integration. options.UseSystemNetHttp(); // Register the ASP.NET Core host. options.UseAspNetCore(); }); services.AddScoped<IAuthorizationHandler , RequireScopeHandler>(); services.AddAuthorization(options => { options.AddPolicy("dataEventRecordsPolic y", policyUser => { policyUser.Requirements.Add(new RequireScope()); }); }); Теперь, я запускаю все эти проекты. Перехожу на страницу, выдаваемую клиентом. Далее перехожу перехожу к защищённой части клиента(помечена [Authorize]). Меня перенаправляет на страницу логина сервера авторизации. Логинюсь и меня пускает к защищённой странице клиента. После пытаюсь отправлять запрос к серверу ресурсов и получаю в ответ 401 или 403. Вот запрос: fetch('https://localhost:44390/api/dataeventrecords', { method: 'GET', credentials: 'include', headers: { "Content-Type": "application/json", "withcredentials": "true", } }); И вопрос: Как сделать, чтобы мнге дал доступ этот грёбаный сервер ресурсов?
0
|
![]() ![]() 13433 / 8964 / 1324
Регистрация: 21.01.2016
Сообщений: 33,651
|
||
21.07.2023, 12:09 | ||
AddOpenIddict и всё с этим связанное?Всё, что от сервера ресурсов (читай: апишка) требуется - просто провалидировать JWT. Оно может сделать это родными средствами, без OpenIddict . Смотри первую часть этой статьи. Во второй части там руками JWT создают, это тебе не надо. Откуда и как этот JWT был рождён тут уже роли не играет.Добавлено через 14 минут Дополню. У тебя имеется два объекта авторизации: веб-приложение и WebAPI. В первое ты входишь по протоколу OpenIDConnect, с редиректами и выдачей куки в конце. Это у тебя работает. А вот для WebAPI требуется Access Token. Причём, этот токен можно двумя способами использовать. Либо в заголовок подкладывать на каждый запрос (по классике), либо использовать для авторизации в WebAPI и получения обычной куки. Тогда такой JWT надо будет руками провалидировать на стороне WebAPI, чтобы куку выплюнуть. Вариант с кукой лучше варианта с подкладыванием в заголовок только тем, что не надо будет ничего в заголовок подкладывать и валидировать токен можно будет один раз. Тут я ещё могу спросить про один момент: а почему WebAPI у тебя отдельно от веб-приложения? Это ты придерживался требования какого-то или просто следовал какой-то выдуманной формальности? Если последнее, то эту апишку можно перенести в веб-приложение, тогда на неё будет действовать кука получаемая при авторизации через OpenID Connect. Если требование соблюдаешь, то тут надо поступать описанным выше способом. Причём, Access Token твоё веб-приложение уже получает во время коллбека от IdP. Не знаю, правда, scope там покрывает апишку или нет (это тебе виднее, как у тебя там всё организованно). Если покрывает, то ты можешь браузеру этот токен вернуть сразу при первом рендере страницы. А дальше уже подкладывать этот токен в заголовок или авторизоваться с его помощью в WebAPI. Последнее из коробки не идёт, надо будет руками это делать, что на клиенте, что на стороне апишки.
1
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 13:16 [ТС] | |
Usaga, Вот ещё такое суждение. Я запрашиваю токен у сервера авторизации. Логинюсь и т.п. Он мне отдаёт токен в заголовках, который куда-то нужно сохранить и потом отправлять всем защищённым api.
Что если бы сервер возвращал не токен, а куку, а потом она бы отправлялась со всеми запросами к апишке? Если такое возможно, то как это реализовать? И нужно ли вообще такое делать?
0
|
0 / 0 / 0
Регистрация: 22.11.2019
Сообщений: 15
|
|
21.07.2023, 13:34 [ТС] | |
Usaga, Благодарю за разъяснения.
Добавлено через 4 минуты Usaga, вообще смысл в том, что будет несколько react.js приложений (по идее будет какое-то общее, которое будет в себя включать остальные). И вот со всех этих приложений будут приходить запросы к апишкам. Но авторизация должна быть общей, чтобы всё в итоге выглядело как одно большое приложение. Как-то так.
0
|
![]() ![]() 13433 / 8964 / 1324
Регистрация: 21.01.2016
Сообщений: 33,651
|
|
21.07.2023, 13:42 | |
jekamaster, ну я так и понял, ситуация-то типичная)
0
|
21.07.2023, 13:42 | |
Помогаю со студенческими работами здесь
20
Разница между ASP.NET Core 2, ASP.NET Core MVC, ASP.NET MVC 5 и ASP.NET WEBAPI 2 Asp Net Core разница между MVC шаблоном, API, Frontend фреймворки
Почему скрипт из ASP.NET MVC 5 не работает в ASP.NET Core? Очистка cookies в ASP.NET Core Identity Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Опции темы | |
|
Новые блоги и статьи
![]() |
||||
Реализация многопоточных сетевых серверов на Python
py-thonny 16.05.2025
Когда сталкиваешься с необходимостью писать высоконагруженные сетевые сервисы, выбор технологии имеет критическое значение. Python, со своей элегантностью и высоким уровнем абстракции, может. . .
|
C# и IoT: разработка Edge приложений с .NET и Azure IoT
UnmanagedCoder 16.05.2025
Мир меняется прямо на наших глазах, и интернет вещей (IoT) — один из главных катализаторов этих перемен. Если всего десять лет назад концепция "умных" устройств вызывала скептические улыбки, то. . .
|
Гибридные квантово-классические вычисления: Примеры оптимизации
EggHead 16.05.2025
Гибридные квантово-классические вычисления — это настоящий прорыв в подходах к решению сложнейших вычислительных задач. Представьте себе союз двух разных миров: классические компьютеры, с их. . .
|
Использование вебсокетов в приложениях Java с Netty
Javaican 16.05.2025
HTTP, краеугольный камень интернета, изначально был спроектирован для передачи гипертекста с минимальной интерактивностью. Его главный недостаток в контексте современных приложений — это. . .
|
Реализация операторов Kubernetes
Mr. Docker 16.05.2025
Концепция операторов Kubernetes зародилась в недрах компании CoreOS (позже купленной Red Hat), когда команда инженеров искала способ автоматизировать управление распределёнными базами данных в. . .
|
Отражение в C# и динамическое управление типами
stackOverflow 16.05.2025
Reflection API в . NET — это набор классов и интерфейсов в пространстве имён System. Reflection, который позволяет исследовать и манипулировать типами, методами, свойствами и другими элементами. . .
|
Настройка гиперпараметров с помощью Grid Search и Random Search в Python
AI_Generated 15.05.2025
В машинном обучении существует фундаментальное разделение между параметрами и гиперпараметрами моделей. Если параметры – это те величины, которые алгоритм "изучает" непосредственно из данных (веса. . .
|
Сериализация и десериализация данных на Python
py-thonny 15.05.2025
Сериализация — это своего рода "замораживание" объектов. Вы берёте живой, динамический объект из памяти и превращаете его в статичную строку или поток байтов. А десериализация выполняет обратный. . .
|
Чем асинхронная логика (схемотехника) лучше тактируемой, как я думаю, что помимо энергоэффективности - ещё и безопасность.
Hrethgir 14.05.2025
Помимо огромного плюса в энергоэффективности, асинхронная логика - тотальный контроль над каждым совершённым тактом, а значит - безусловная безопасность, где безконтрольно не совершится ни одного. . .
|
Многопоточные приложения на C++
bytestream 14.05.2025
C++ всегда был языком, тесно работающим с железом, и потому особеннно эффективным для многопоточного программирования. Стандарт C++11 произвёл революцию, добавив в язык нативную поддержку потоков,. . .
|