Реєстрація зовнішніх логінів Web API 2 від декількох клієнтів API за допомогою OWIN Identity


75

Я хотів би мати таку архітектуру (для цього прикладу я склав назву продукту):

Додаток Web API 2 працює на одному сервері http://api.prettypictures.com

Клієнтська програма MVC 5 працює на іншому сервері http://www.webpics.com

Я хотів би www.webpics.com клієнтська програма використовувала API Pretty Pictures для:

  • Зареєструйте нові акаунти за допомогою імені користувача та пароля
  • Зареєструйте нові акаунти у Facebook / Google / Twitter / Microsoft
  • Увійдіть
  • Отримати фотографії

Все вищезазначене працює, крім реєстрації зовнішніх акаунтів у Facebook, Google тощо.

Я не можу визначити правильний процес створення зовнішнього облікового запису від окремого клієнта-користувача API.

Я вивчив більшість документів, доступних у процесі аутентифікації, наприклад: введіть тут опис зображення

Я прочитав майже все, що можу, про нову модель ідентичності в OWIN.

Я розглянув шаблон SPA у Visual Studio 2013. Він демонструє, як зробити більшу частину того, що мені потрібно, але лише тоді, коли клієнт і API знаходяться на одному хості; якщо я хочу, щоб кілька клієнтів отримували доступ до мого API і мали можливість дозволити користувачам реєструватися через Google тощо, це не працює, і, наскільки я можу сказати, потік автентифікації OWIN переривається.

Ось такий потік:

  • Користувач переходить на веб- сторінку www.webpics.com/Login
  • www.webpics.com викликає api.prettypictures.com/Account/ExternalLogins (із функцією returnUrl, встановленою для повернення до зворотного дзвінка на www.webpics.com ) і відображає отримані посилання користувачеві
  • Користувач натискає "Google"
  • Браузер переспрямовує на api.prettypictures.com/Account/ExternalLogin з іменем постачальника тощо.
  • Дія API ExternalLogin створює виклик google.com
  • Браузер перенаправляється на google.com
  • Користувач вводить своє ім’я користувача та пароль (якщо він ще не ввійшов у систему на google.com )
  • google.com тепер представляє дозвіл на безпеку: "api.prettypictures.com" хоче отримати доступ до вашої адреси електронної пошти, імені, дружини, дітей тощо. Це нормально?
  • Користувач натискає "Так" і повертається до api.prettypictures.com/Account/ExternalLogin із файлом cookie, який встановив Google.

Тут я застряг. Що має відбутися далі, так чи інакше клієнтську програму слід повідомити про те, що користувач успішно пройшов автентифікацію за допомогою google.com і отримати одноразовий код доступу для заміни на маркер доступу пізніше. Клієнтський додаток повинен мати можливість, якщо це необхідно, запропонувати користувачеві ввести ім’я користувача для зв’язку з його логіном google.com .

Я не знаю, як сприяти цьому.

Насправді на цей момент браузер після зворотного дзвінка від Google закінчується сідати на кінцеву точку api.prettypictures.com/Account/ExternalLogin . API ввійшов у систему Google, але клієнт не знає, як з цим боротися. Чи слід передавати цей файл cookie назад на www.webpics.com ?

У програмі SPA це робиться через AJAX, і google.com поверне маркер у вигляді фрагмента URL-адреси, і все це чудово працює, оскільки все це знаходиться в одному домені. Але це суперечить більшій частині сенсу наявності "API", який можуть повною мірою використовувати багато клієнтів.

Допоможіть!


Ей Джош! В даний час я теж працюю над цим. У нас є Web Api та html5 / angularJS SPA, які ми хочемо засвідчити за допомогою google / facebook. У вас немає блогу чи репозиторію github з демонстрацією того, як ви це вирішили? Було б дуже цікаво!
Ашкан Говольд

Привіт Ашкане, на жаль, ні! Ви використовуєте SPA на іншому домені, ніж веб-API (як зазначено вище)?
joshcomley

Так, ми розробляємо додаток phonegap, тому у нас є веб-API як наш серверний сервіс і чистий html5 / angularjs SPA як наш інтерфейс в іншому домені, це згодом стане додатком, який буде отримувати доступ до API з телефонів користувачів.
Ashkan Hovold

Джош чи @AshkanAldini, ти врешті вирішив це? Я намагаюся зробити щось подібне, і відповідь Pinpoint була корисною, але все ще бентежусь щодо реалізації.
Mayabelle

Відповіді:


46

Оновлення: речі змінилися з моменту написання цього допису в січні : MSFT випустила офіційне проміжне програмне забезпечення клієнта OpenID connect, і я наполегливо працював з @manfredsteyer, щоб адаптувати сервер авторизації OAuth2, побудований у Катані, до OpenID connect. Ця комбінація призводить до набагато простішого та набагато потужнішого рішення, яке не потребує спеціального коду клієнта і на 100% сумісне зі стандартними клієнтами OAuth2 / OpenID підключення. Різні кроки, про які я згадав у січні, тепер можна замінити лише кількома рядками:

Сервер:

app.UseOpenIdConnectServer(options =>
{
    options.TokenEndpointPath = new PathString("/connect/token");
    options.SigningCredentials.AddCertificate(certificate);

    options.Provider = new CustomOpenIdConnectServerProvider();
});

Клієнт:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    Authority = "http://localhost:55985/",

    ClientId = "myClient",
    ClientSecret = "secret_secret_secret",
    RedirectUri = "http://localhost:56854/oidc"
});

Ви можете знайти всі деталі (та різні зразки) у сховищі GitHub:

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy


Джош, ти точно на правильному шляху і твій делегована / федеративна реалізація автентифікації здається досить хорошою (я думаю, що ти використовував попередньо визначений проміжний простір OWINMicrosoft.Owin.Security.Facebook/Google/Twitter ).

Вам потрібно створити власний сервер авторизації OAuth2 . У вас є безліч варіантів досягти цього, але найпростіший - це, мабуть, підключитиOAuthAuthorizationServerMiddleware ваш клас OWIN Startup. Ви знайдете це вMicrosoft.Owin.Security.OAuth пакунку Nuget.

Хоча найкращою практикою було б створити окремий проект (який часто називають "AuthorizationServer"), я особисто вважаю за краще додавати його до свого "проекту API", коли він не призначений для використання в декількох API (тут вам доведеться вставити у хостингу проекту "api.prettypictures.com").

Ви знайдете чудовий зразок у сховищі Katana:

https://katanaproject.codeplex.com/SourceControl/latest#tests/Katana.Sandbox.WebServer/Startup.cs

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
    TokenEndpointPath = new PathString("/oauth2/token"),
    ApplicationCanDisplayErrors = true,

    AllowInsecureHttp = true,

    Provider = new OAuthAuthorizationServerProvider
    {
        OnValidateClientRedirectUri = ValidateClientRedirectUri,
        OnValidateClientAuthentication = ValidateClientAuthentication,
        OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
    },
    AuthorizationCodeProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateAuthenticationCode,
        OnReceive = ReceiveAuthenticationCode,
    },
    RefreshTokenProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateRefreshToken,
        OnReceive = ReceiveRefreshToken,
    }
});

Не соромтеся переглядати весь проект, щоб побачити, як реалізована форма згоди на авторизацію за допомогою простих файлів Razor. Якщо ви віддаєте перевагу фреймворк вищого рівня, такий як ASP.NET MVC або NancyFX, створіть власний AuthorizationControllerконтролер і Authorizeметоди (переконайтеся, що приймаєте і GET, і POST) і використовуйте маршрутизацію атрибутів, щоб відповідати AuthorizeEndpointPath, визначеному на вашому сервері авторизації OAuth2 (тобто [Route("oauth2/authorize")]в мій зразок, де я змінив AuthorizeEndpointPathдля використання oauth2/як основу шляху).

Інше, що вам потрібно зробити, - це додати клієнт авторизації OAuth2 у свій веб-додаток. На жаль, у Katana немає загальної підтримки клієнтів OAuth2, і вам доведеться створити свою власну. Я особисто подав пропозицію команді Katana, але вона отримала відмову. Але не панікуйте, зробити це досить просто:

Скопіюйте відповідні файли зі сховища Microsoft.Owin.Security.Google, розташованого там: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs

Вам потрібно GoogleOAuth2AuthenticationHandler, GoogleOAuth2AuthenticationMiddleware, GoogleOAuth2AuthenticationOptions, GoogleAuthenticationExtensions(вам доведеться видалити перші 2 методу , відповідні реалізації Google OpenID), IGoogleOAuth2AuthenticationProvider, GoogleOAuth2ReturnEndpointContext, GoogleOAuth2AuthenticationProvider, GoogleOAuth2AuthenticatedContextі GoogleOAuth2ApplyRedirectContext. Після того, як ви вставите ці файли у свій проект, що розміщує "webpics.com", перейменуйте їх відповідно і змініть URL-адресу кінцевих точок авторизації та доступу вGoogleOAuth2AuthenticationHandler на відповідність тим, які ви визначили на своєму сервері авторизації OAuth2.

Потім додайте метод Use із вашого перейменованого / спеціального GoogleAuthenticationExtensionsдо вашого класу запуску OWIN. Я пропоную використовувати, AuthenticationMode.Activeщоб ваші користувачі були безпосередньо перенаправлені на вашу кінцеву точку авторизації API OAuth2. Таким чином, вам слід придушити круговий шлях "api.prettypictures.com/Account/ExternalLogins" і дозволити клієнтському програмному забезпеченню OAuth2 змінити 401 відповідь для перенаправлення клієнтів на ваш API.

Удачі. І не соромтеся, якщо вам потрібна додаткова інформація;)


Привіт, дякую за вашу відповідь, це в значній мірі вказало мені у всіх правильних напрямках, і я майже там. Я створив власну реалізацію проміжного програмного забезпечення, використовуючи класи, на які ви вказали. На чому я застряг, це коли я перенаправляю назад до оригіналу клієнта redirect_uri, наприклад http://www.webpic.com/signin-prettypictures, що я вкладаю в рядок запиту, щоб журнали проміжного програмного забезпечення знали, що робити?
joshcomley

(Я намагався помістити стан там як параметр рядка запиту, але проміжне програмне забезпечення, здається, просто його проковтнуло і перенаправило на домашню сторінку мого клієнта)
joshcomley

Чудово чути! Я не знаю, чи ви вирішили останню проблему, але я думаю, що налаштування RedirectUri на AuthenticationProperties передається IAuthenticationManager.Challenge зробить свою справу;)
Kévin Chalet

1
@mayabelle: звичайно, будь ласка, дивіться мою відповідь тут: stackoverflow.com/questions/28487586/…
Кевін Шале

1
@CularBytes Я подивлюсь на ваш інший "POST"
гідний7
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.