ЗАБЕЗПЕЧНО спроектувати / увійти або / зареєструвати ресурси?


122

Я розробляв веб-додаток, а потім перестав думати про те, як мій api повинен бути розроблений як RESTful веб-сервіс. Наразі більшість моїх URI є загальними і можуть застосовуватися до різних веб-додатків:

GET  /logout   // destroys session and redirects to /
GET  /login    // gets the webpage that has the login form
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx
GET  /user/xxx // gets and renders current user data in a profile view
POST /user/xxx // updates new information about user

У мене є відчуття, що я роблю тут багато неправильного після того, як тикаю на SO та Google.

Почнемо з того /logout, можливо, оскільки я нічого не роблю GET- може бути більш доречним POSTзапит /logout, знищити сеанс, а потім GETперенаправити. І чи повинен /logoutтермін залишатися?

Що про /loginі /register. Я міг би змінити , /registerщоб , /registrationале це не змінює , як моя служба в основному працює - якщо вона має більш глибокі питання.

Зараз я помічаю, що ніколи не виставляю /userресурс. Можливо, це можна було б якось використати. Наприклад, візьміть користувача myUser:

foo.com/user/myUser

або

foo.com/user

Кінцевому користувачеві не потрібна додаткова багатослівність у URI. Однак, хто з них є більш привабливим візуально?

Тут я помітив деякі інші питання на ТАК щодо цього бізнесу REST, але я дуже вдячний, коли б це було можливо, деякі поради щодо того, що я виклав тут.

Дякую!

ОНОВЛЕННЯ:

Я також хотів би отримати декілька думок щодо:

/user/1

проти

/user/myUserName

Відповіді:


63

Зокрема, одна річ не відрізняється від REST-ful: використання GET-запиту для виходу з системи.

http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods )

Деякі методи (наприклад, HEAD, GET, OPTIONS та TRACE) визначені як безпечні, це означає, що вони призначені лише для пошуку інформації та не повинні змінювати стан сервера. Іншими словами, вони не повинні мати побічних ефектів, крім відносно нешкідливих ефектів, таких як реєстрація, кешування, розміщення реклами банерів або збільшення веб-лічильника. [...]

[... H] andling [від GET-запитів] сервером технічно ні в якому разі не обмежується. Тому недбале або навмисне програмування може спричинити нетривіальні зміни на сервері. Це не рекомендується, оскільки це може спричинити проблеми з кешуваннями веб-сайтів, пошуковими системами та іншими автоматизованими агентами [...]

Що стосується виходу та переадресації, ви можете мати публікацію на URI виходу, щоб дати відповідь 303 на сторінку після виходу.

http://en.wikipedia.org/wiki/Post/Redirect/Get

http://en.wikipedia.org/wiki/HTTP_303

Редагувати, щоб вирішити питання щодо дизайну URL-адрес:

"Як я проектую свої ресурси?" для мене важливе питання; "як я створюю свої URL-адреси?" це розгляд у двох сферах:

URL-адреси, які бачать користувачі, не повинні бути надто негарними та значущими, якщо це можливо; якщо ви хочете, щоб куки надсилалися в запитах на якийсь ресурс, але не на інші, ви хочете структурувати свої шляхи та шляхи cookie.

Якщо JRandomUserви хочете подивитися на його власний профіль, і ви хочете, щоб URL-адреса була красивішою foo.com/user/JRandomUserабо foo.com/user/(JRandom's numeric user id here), ви можете зробити окрему URL-адресу лише для того, щоб користувач міг переглянути власну інформацію:

GET foo.com/profile /*examines cookies to figure out who 
                     * is logged in (SomeUser) and then 
                     * displays the same response as a
                     * GET to foo.com/users/SomeUser.
                     */

Я б сказав про незнання набагато легше, ніж про мудрість з цього приводу, але ось декілька міркувань щодо дизайну ресурсів:

  1. Споживач: які ресурси призначені для перегляду безпосередньо у веб-переглядачі, завантажені через XHR або доступ до якогось іншого клієнта?
  2. Доступ / ідентичність: чи залежить відповідь від файлів cookie чи рефератів?

1
Чудова відповідь, дякую! Якби я збирався реалізувати вашу окрему пропозицію щодо URL-адреси ( GET foo.com/profile/), чи буде це частиною шару презентації, як запропонував momo? Іншими словами, що саме повинен GETповернути цей запит? Веб-сторінка чи якийсь JSON?
Qcom

2
А, я думаю, зараз бачу. Відповідь Момо дійсно прояснила речі. Таким чином, RESTful API побудований , щоб дозволити кілька платформ GET, POST, PUTі DELETEресурсів. Веб-сайт - це ще одна платформа для доступу до API. Іншими словами, дизайн URL-адреси веб-сайту зовсім інший, ніж дизайн RESTful API. Скажіть, будь ласка, чи я все-таки помиляюся ха-ха.
Qcom

Так, зробіть свій REST API один набір URL-адрес, а веб-сайт - інший. Тоді URL вашого веб-сайту повинен повернути вам відповідний HTML + Javascript, щоб сторінка зробила відповідні XmlHttpRequests до ваших URL-адрес API, щоб діяти як клієнт.
ellisbben

129

RESTful може використовуватися як орієнтир для створення URL-адрес, і ви можете створювати сеанси та користувацькі ресурси:

  • GET /session/new отримує веб-сторінку, яка має форму входу
  • POST /session аутентифікує облікові дані щодо бази даних
  • DELETE /session знищує сеанс і перенаправляє на /
  • GET /users/new отримує веб-сторінку, яка має форму реєстрації
  • POST /users записує введену інформацію в базу даних як новий / користувач / ххх
  • GET /users/xxx // отримує та відображає поточні дані користувачів у режимі перегляду профілю
  • POST /users/xxx // оновлює нову інформацію про користувача

Вони можуть бути множиною чи одниною (я не впевнений, який із них правильний). Зазвичай я використовую /usersдля індексної сторінки користувача (як очікувалося) і /sessionsщоб побачити, хто входить (як очікувалося).

Використання імені в URL-адресі замість числа ( /users/43проти /users/joe) зазвичай обумовлюється прагненням бути більш привітними до користувачів або пошукових систем, а не будь-якими технічними вимогами. Або добре, але я б рекомендував вам бути послідовними.

Я думаю, якщо ви перейдете з реєстрацією / входом / виходом або sign(in|up|out), це не добре працює з термінологією спокою.


6
Дивовижно! Мені подобається, як ти називав ці ресурси; це досить чисто. Хоча, з того, що я чув, не додається /newдо GET /session/не RESTful? Я чув , що дієслова , як правило , зліва від HTTP дієслів ( GET, POST, і т.д.).
Qcom

2
@Zach new - не дієслово. У цьому випадку це підресурс сеансу.
Кугель

Як визначити, який сеанс видалити в DELETE / сесії? Curl не надсилає ні cookie, ні параметри в DELETE-запиті. Я припускаю - просто використовувати DELETE / session / sessionId? Інше питання - як повернути ідентифікатор сеансу в POST / сесії та в якому форматі.
Tvaroh

9
Відпочинок справді - це спосіб зробити себе нещасним і витратити час на речі, які зовсім не мають значення.
Цзянь Чен

6
Особисто мені не подобається ідея мати маршрути, які повертають форму (/ нову). Це порушує поділ між поглядом та логікою бізнесу. Tha сказав, без запропонованих маршрутів / нових маршрутів виглядає ідеально.
Схід

60

Сесії не є ВІДБУДОВИМИ

  • Так, я знаю. Це робиться, як правило, з OAuth, але насправді сеанси не є ВИПАДКІ. У вас не повинно бути ресурсу / login / вихід, головним чином через те, що у вас не повинно бути сеансів.

  • Якщо ви збираєтеся це зробити, зробіть це ВИПУСКНО. Ресурси є іменниками, і / login та / logout не є іменниками. Я б пішов з / сеансом. Це робить створення та видалення більш природним дією.

  • POST vs. GET для сеансів легко. Якщо ви надсилаєте користувача / пароль як змінні, я б використовував POST, оскільки я не хочу, щоб пароль надсилався як частина URI. Він відображатиметься в журналах і, можливо, виявиться над дротом. Ви також ризикуєте вийти з ладу програмного забезпечення за обмеженнями аргументів GET.

  • Зазвичай я використовую Basic Auth або немає Auth з послугами REST.

Створення користувачів

  • Це один ресурс, тому вам не потрібно / реєструватися.

    • POST / user - створює користувача, якщо запитувач не може вказати ідентифікатор
    • PUT / user / xxx - Створіть або оновіть користувача, якщо ви заздалегідь знаєте його
    • GET / user - перелічує x ідентифікатори користувачів
    • GET / user / xxx - Отримує реквізити користувача з id xxx
    • DELETE / user / xxx - Видаліть користувача з id xxx
  • Який тип ідентифікатора використовувати важко. Ви повинні думати про застосування унікальності, про повторне використання старих ідентифікаторів, які були DELETEd. Наприклад, ви не хочете використовувати ці ідентифікатори як сторонні ключі в бекенді, якщо ідентифікатори збираються переробити (якщо це взагалі можливо). Ви можете здійснити пошук, хоча для перетворення зовнішнього / внутрішнього ідентифікатора, щоб зменшити вимоги до бекенда.


6
Це найкраща відповідь. / login та / logout - це не ресурси та порушують ідею REST.
wle8300

5
Автентифікація! = Сесія
дієтабудди

1
Так, у розділі 5.1.3 теза Філдінга зазначає, що "стан есе [...] повністю зберігається на клієнті". Далі я б заперечував, що в ідеалі аутентифікація також повинна бути без стану на сервері, тобто замість того, щоб зберігати в базі даних активні "автентифікаційні квитки", сервер повинен мати можливість перевірити обліковий запис автентифікації просто на основі самого облікового запису, наприклад, використовуючи самостійний криптографічний маркер у поєднанні з приватним ключем. Отже, замість ресурсу / сеансу можна було б запровадити ресурс / автентифікацію, але він теж не вирішує проблему ...
raner

Власне, / login та / logout є іменниками. Я припускаю, що ви думаєте про / log_in та / log_out.
TiggerToo

21

Я буду просто говорити зі свого досвіду, інтегруючи різні веб-сервіси REST для своїх клієнтів, будь то для мобільних додатків або для зв'язку з сервером на сервер, а також для побудови REST API для інших. Ось кілька спостережень, які я зібрав з інших програм REST API, а також тих, які ми створили самі:

  • Коли ми говоримо API, він зазвичай стосується набору інтерфейсу програмування, а не необхідний рівень презентації. REST також орієнтований на дані та не керується презентацією. Це говорить про те, що більшість REST повертають дані у вигляді JSON або XML і рідко повертають певний рівень презентації. Ця ознака (повернення даних, а не пряма веб-сторінка) давала можливість REST здійснювати доставку багатоканальних каналів. Це означає, що ту саму веб-службу можна надавати в HTML, iOS, Android або навіть використовувати як комбінацію сервер-сервер.
  • Дуже рідко поєднувати як HTML, так і REST як URL. За замовчуванням REST - це думки як послуги, що не мають шару презентації. Завданням тих, хто споживає веб-сервіси, є надання даних із служб, які вони викликають, відповідно до того, що вони хочуть. З цього моменту, ваша URL-адреса нижче не відповідає більшості проектів на основі REST, з якими я стикався дотепер (ні стандартам, таких як ті, що надходять з Facebook чи Twitter)
GET / register // отримує веб-сторінку, яка має форму реєстрації
  • Продовжуючи з попереднього пункту, також нечасто (і я не стикався) для служби на базі REST робити перенаправлення, наприклад, запропоновані нижче:
GET / вихід / // знищує сеанс та переспрямовує на /
POST / login // автентифікує облікові дані проти бази даних і або перенаправляє додому з нового сеансу, або переспрямовує назад до / login
 

Оскільки REST розроблені як послуги, такі функції, як вхід та вихід, зазвичай повертають результат успіху / відмови (як правило, у форматі даних JSON або XML), який тоді споживач інтерпретуватиме. Таке тлумачення може включати перенаправлення на відповідну веб-сторінку, як ви згадували

  • У REST URL-адреса позначає дії, які виконуються. З цієї причини нам слід усунути якомога більше двозначності. Хоча у вашому випадку законно мати як GET, так і POST, які мають однаковий шлях (наприклад, / реєстрація), які виконують різні дії, такий дизайн вносить неоднозначність у надані послуги та може заплутати споживача ваших послуг. Наприклад, такі URL-адреси, які ви вводите нижче, не ідеально підходять для послуг на базі REST
GET / register // отримує веб-сторінку, яка має форму реєстрації
POST / register // записує введену інформацію в базу даних як новий / користувач / xxx

Це деякі моменти, з яких я мав справу. Я сподіваюся, що це може дати вам деяку інформацію.

Що ж стосується впровадження вашого REST, то це типова реалізація, з якою я стикався:

  • GET / вихід  
    

    Виконайте вихід із сервера та поверніть JSON для позначення успіху / провалу операції

  • POST / логін
    

    Надішліть облікові дані до бекенда. Повернути успіх / невдачу. Якщо це буде успішно, зазвичай він також поверне маркер сеансу, а також інформацію про профіль.

  • POST / реєстр
    

    Надішліть реєстрацію до бекенда. Повернути успіх / невдачу. Якщо це успішно, зазвичай трактується так само, як успішний логін, або ви можете вибрати реєстрацію як окрему послугу

  • GET / користувач / ххх
    

    Отримайте профіль користувача та поверніть формат даних JSON для профілю користувача

  • POST / користувач / ххх 
    // перейменований на 
    POST / updateUser / xxx
    

    Опублікуйте оновлену інформацію профілю у форматі JSON та оновіть інформацію у вихідному. Повернення успіху / невдачі абоненту


3
Так, якщо ви інтегруєте свій REST API з додатком на базі HTML (через Javascript і AJAX), ви отримаєте величезні переваги, оскільки JSON синтаксично розбирає Javascript. В Android / Java JSON простіше і простіше розібратися, порівняно з XML.
momo

15
GET / вихід із системи небезпечний. GET повинен бути безсильним. Також браузери люблять попередньо вибирати <a> hrefs, які вийдуть із системи!
Кугель

4

Я вважаю, що це РІЗНИЙ підхід до аутентифікації. Для входу ви використовуєте HttpPut. Цей метод HTTP може бути використаний для створення, коли ключ наданий, і повторні дзвінки є ідентичними. Для LogOff ви вказуєте той самий шлях у HttpDeleteметоді. Не вживаються дієслова. Правильна плюралізація колекції. Методи HTTP підтримують цю мету.

[HttpPut]
[Route("sessions/current")]
public IActionResult LogIn(LogInModel model) { ... }

[HttpDelete]
[Route("sessions/current")]
public IActionResult LogOff() { ... }

При бажанні ви можете замінити струм на активний.


1

Я рекомендую використовувати URL-адресу облікового запису користувача, схожу на twitter, де URL-адреса облікового запису користувача буде щось подібне, foo.com/myUserNameяк ви можете потрапити до мого акаунта Twitter із URL-адресою https://twitter.com/joelbyler

Я не погоджуюся з тим, що вихід із системи вимагає POST. Якщо ви збираєтеся підтримувати сеанс, то ваш ідентифікатор сеансу у формі UUID може бути чимось, що може бути використане для відстеження користувача та підтвердження того, що вжиті дії є дозволеними. Тоді навіть GET може передавати ідентифікатор сеансу до ресурсу.

Коротше кажучи, я б рекомендував робити це просто, URL-адреси повинні бути короткими, що запам'ятовуються.


Питання стосується ресурсів API. Ваша відповідь стосується шару презентації.
Henno
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.