ICSI301 Төсөл 7: Сесшн ба оролт

Энэ төсөлд хэрэглэгчдэд нэвтрэх, зураг дээр сэтгэгдэл бичих, шинэ зураг серверт хуулах замаар Төсөл 6-аар хийсэн ажлаа өргөтгөнө. Эдгээр шинэ функцийн нэмэлтүүд нь бүтэн стек (full stack) хөгжүүлэлт тул та фронтэнд (React програм) болон бакэнд (Node вэб сервер болон MongoDB өгөгдлийн сан) хоёуланг нь өөрчлөх шаардлагатай.

Тохиргоо

Та өөрийн системд MongoDB болон Node.js суулгасан байх ёстой. Хэрвээ байхгүй бол суулгах заавар дагаж суулгаарай.

Төсөл 6-ийн нэгэн адил өмнөх төслийн хавтсын (project6) файлуудыг project7 нэртэй шинэ хавтасруу хуулж эхэлнэ ( .babelrc болон .eslintrc.json зэрэг зэрэг далдалсан бүх файлуудыг хуулсан эсэхийг шалгаарай). Энэ zip файлыг project7 хавтас дотор задлана. Энэ шахсан файл хэд хэдэн шинэ файл нэмэх юм. project7 хавтас дотор энэ төслийн бүх ажлаа хийгээрэй.

Энэ даалгаврыг хийхийн тулд та хэдэн шинэ node_modules татаж тэдгээрийг вэб сервер болон React програмдаа нэмэх хэрэгтэй болно. Модуль бүрийн хувьд дараах командыг ашиглаж татаж авна уу:

npm install --save <module>
Энэ нь <module> нэртэй модулийг таны node_modules хавтаст татаж, package.json файлд модулийг (dependencies) нэмнэ. Модулийг вэб сервертээ нэмэхийн тулд require функцийг ашиглана.

Та node модулиуддаа дараах Express дундын программ (middleware) татах шаардлагатай болно:
  • express-session - Express сесшн нь сесшнийг өөрөө удирдах гэхээс илүүтэйгээр танд зориулсан Express дундын давхарга юм. Үүнийг лекцээр тайлбарласан.
  • body-parser - body-parser нь HTTP хүсэлтийн бие хэсгийг (body) задлахад зориулсан Express дундын давхарга юм. Та үүнийг өөрсдийн серверийн API-д ашигладаг JSON форматаар кодлогдсон POST хүсэлтүүдийн бие хэсгийг задлахад ашиглаж болно. Жишээлбэл, parameter_name шинжтэй JSON объектыг хүсэлтийн бие хэсэгт дамжуулбал үүнд Express хүсэлт баригчаар request.body.parameter_name гэж хандах боломжтой.
  • multer - multer нь зураг серверт хуулахад шаардлагатай олон хэсэгт маягтуудыг боловсруулах чадвартай, хүсэлтийг бие хэсгийг задлах өөр нэг Express дундын программ юм.

Ихэнх системд дараах командаар дээрх модулиудыг татдаг:

      npm install --save express-session
      npm install --save body-parser
      npm install --save multer

require функцийг дуудах дараах мөрийг webServer.js файлд нэмнэ:

      const session = require("express-session");
      const bodyParser = require("body-parser");
      const multer = require("multer");

Эцэст нь та дараах байдлаар Express use ашиглан express-session болон body-parser дундын программыг нэмэх хэрэгтэй:

      app.use(session({secret: "secretKey", resave: false, saveUninitialized: false}));
      app.use(bodyParser.json());
Энд "secretKey" нь сесшн күүкийг криптографийн аргаар хамгаалахад ашиглах нууц үг. Бид зураг серверт хуулахад multer дунд программыг ашиглах болно.

Хэрэв та 6-р төслийн 2-р даалгаврыг гүйцэтгэсэн бол загваруудыг татахдаа axios модулийг ашиглах хэрэгтэй. Хэрэв та Төсөл 6-д хэрэгжүүлээгүй бол илүү дэлгэрэнгүйг axios баримт бичгээс харна уу.

Өмнөх даалгавартай адил бид серверийн API-г шалгах Mocha тестийг өгсөн тул фронт-энд хэсгээр хөгжүүлэхээс өмнө бак-энд код найдвартай ажиллаж буйд итгэлтэй байх боломжийг олгоно. Энэ боломжийн хариуд та бидний тодорхойлсон серверийн API-г хэрэгжүүлэх хүрээнд хязгаарлагдаж хөгжүүлнэ. Энэ нь та кодоо илгээхээсээ өмнө бидний өгсөн тестийг давж байгаа эсэхээ шалгах боломжтой гэсэн үг. Дэлгэрэнгүй мэдээллийг доорх Тест хэсгээс үзнэ үү. Хэрэв та 6-р төслийн нэмэлт онооны даалгаврыг хийж API-аа өргөтгөсөн бол үүнийг шалгах тестээ өөрөө нэмж бичих шаардлагатай. Хэрэв энэ төсөлд нэмэлт онооны даалгаврыг хийхээр шийдсэн бол нэмэлт тестийг бас давах шаардлагатай болно.

Өмнөх төслийн нэгэн адил та MongoDB өгөгдлийн сангийн системээ асаах хэрэгтэй болно. MongoDB-г дараах командаар ажиллуулж эхлүүлнэ үү:

mongod (өгөгдлийн санг хаана байршуулснаас хамаарсан тодорхой аргументууд)
мөн дараах командыг ажиллуулж зургийн программын өгөгдлийг өгөгдлийн санд хуулна уу:
node loadDatabase.js
Энэ командын Төсөл 7-д өгсөн хувилбар нь хэрэглэгчийн объектыг login_name (овгийн last_name жижиг үсгээр бичсэн хувилбар) болон "weak" гэсэн нууц үгээр хуулдаг болохыг анхаарна уу. Эдгээр шинж нь зөвхөн моделийн схемд талбаруудыг нэмсний (1-р даалгавар) дараа loadDatabase.js кодыг ажиллуулах үед гарч ирнэ.

Node.js вэб серверийг эхлүүлэх нь

Өгөгдлийн сангаа байгуулж системээ асаасны дараа вэб серверээ асаах хэрэгтэй болно. Хэдийгээр үүнийг өмнөх даалгавруудтай ижил командаар (жишээ нь, node webServer.js), хийж болох ч webServer.js кодыг өөрчлөх үед автоматаар дахин эхлүүлэх програм ашиглан вэб серверийг ажиллуулах нь илүү тохиромжтой. Үгүй бол та хийсэн кодын өөрчлөлт бүрийн дараа вэб серверээ дахин асаахаа мартсан үед таны өөрчлөлт яагаад ажиллахгүй болсныг гайхан цаг хугацаа зарцуулж магадгүй.

Дараах команд
npm install -g nodemon
серверийг автоматаар дахин ажиллуулдаг nodemon нэртэй программыг суулгана (та sudo командыг ашиглах хэрэгтэй байж магадгүй). -g параметртэйгээр ажиллуулбал нь програмыг global байдлаар суулгадаг тул та хаана ч ажиллуулах боломжтой. project7 хавтас дотроос дараах командаар вэб серверээ асаана:
nodemon webServer.js
Энэ команд вэб серверийг ажиллуулж, webServer.js файл өөрчлөгдөх бүрт дахин эхлүүлэх болно. Хэрэв Node програмаас гарахад хүргэдэг алдаа (жишээ нь, ЖаваСкрипт бичлэгийн дүрмийн алдаа) гарвал nodemon webServer.js файлыг өөрчлөх хүртэл хүлээж, дараа нь дахин эхлүүлэхийг оролдоно. Хэрэв та файлыг өөрчлөхгүйгээр вэб серверийг дахин эхлүүлэхийг хүсвэл nodemon командын rs гэсэн хоёр тэмдэгт командыг бичиж гараар дахин эхлүүлж болно. Та Node.js кодоос лог зурвасыг (logging messages) гаргаж харахдаа үүнийг өөрийн хөгжүүлэлтийн орчны цонх эсвэл терминал дээрээ ажиллуулах хэрэгтэй.

Төсөл 7-ийн шинэ файлуудаар өөрийн Photo Share программаа шинэчилж өгөгдлийн сан болон вэб серверийг ажиллуулсны дараа, даалгавараа хийж эхлэхээсээ өмнө программаа ажиллаж байгаа эсэхийг шалгана.

Даалгавар 1: Энгийн нэвтрэлт (15 оноо)

Хэрэглэгч нэвтэрдэг гэсэн ойлголттой болохын тулд зургийн аппаа өргөтгөнө. Хэрэв хэрэглэгч нэвтэрсэн бол хэрэгслийн талбарт (toolbar) "Hi <firstname>" гэсэн товч зурвас байх бөгөөд энд <firstname> нь нэвтэрсэн хэрэглэгчийн нэр байна. Хэрэгслийн талбар нь хэрэглэгчийг гаргах "Logout" товчийг мөн агуулах ёстой.

Хэрэв нэвтэрсэн хэрэглэгч байхгүй бол хэрэгслийн талбарт "Please Login" гарч ирэх бөгөөд таны программын үндсэн хэсэгт LoginRegister нэртэй шинэ харагдац (view) компонент гарч ирнэ. LoginRegister компонент нь хэрэглэгчийг нэвтрэх арга замыг, доорх 4-р даалгаврын нэг хэсэг болох шинэ хэрэглэгчийг бүртгэх боломжийг хамт зааж өгнө. Өөр харагдац руу шилжих бусад бүх оролдлого (жишээ нь, гүн холбоос) нь хэрэглэгч нэвтэрч ороогүй тохиолдолд LoginRegister харагдац руу шилжүүлдэг байна. (Хэрэв та үүнийг хэрхэн хэрэгжүүлэхээ мэдэхгүй байгаа бол зөвлөмж хэсгийг үзнэ үү.) Үүнээс гадна, хэрэв хэрэглэгч нэвтрээгүй бол зүүн талд байгаа хэрэглэгчийн жагсаалтыг харуулах ёсгүй. (401 (Unauthorized) статусыг буцаахын тулд серверийн эндпойнтуудыг өөрчлөх талаар энэ даалгаврын хамгийн доод тайлбарыг үзнэ үү).

Хэрэглэгч амжилттай нэвтэрсэн үед харагдах байдал нь хэрэглэгчийн дэлгэрэнгүй мэдээллийг харуулах хэсэг рүү шилжих ёстой. Хэрэв хэрэглэгчийн нэвтрэлт амжилтгүй болвол (жишээ нь, login_name-тэй хэрэглэгч байхгүй) харагдац нь зохих алдааны мэдэгдлийг мэдээлэх бөгөөд хэрэглэгч дахин оролдох боломжийг олгох юм.

Нэвтэрсэн хэрэглэгч гэх ойлголтыг зургийн аппдаа оруулахын тулд бакэндийн хэрэгжүүлэлтийг өргөтгөнө. Энэ өөрчлөлтийг хийхдээ та өгөгдлийн сангийн схем болон вэб серверийн API хоёуланг нь өөрчлөх шаардлагатай.

User дээр шинэ хэсэг (property) login_name нэмэхийн тулд Mongoose схемийг өргөтгөнө үү.Энэ хэсэг нь хэрэглэгчийн нэвтрэх үед бичих үед танигчийг (тэдний "нэвтрэх нэр") агуулсан тэмдэгт мөр юм.

Вэб серверийн API-г өөрчлөн хэрэглэгчийг нэвтрэх, гаргахын тулд 2 шинэ REST API дуудлагыг хийх хэрэгтэй. Өмнөх даалгаврын нэгэн адил бид загварөн өгөгдлийг дамжуулахын тулд JSON кодлогдсон биетэй HTTP хүсэлтийг ашиглах болно. API нь POST хүсэлтийг дараах зорилгоор ашигладаг:

  • /admin/login - Зургийн програмын LoginRegister харагдац нь хэрэглэгч рүү нэвтрэх боломжийг олгодог. POST хүсэлттэй JSON-кодлогдсон хэсэг нь property login_name (одоохондоо нууц үг байхгүй) агуулсан байх ёстой бөгөөд таны апп-д нэвтэрсэн хэрэглэгчдэд шаардлагатай мэдээллийг агуулсан байх ёстой. Нэвтрэх амжилтгүй болсон тохиолдолд (жишээ нь , login_name хүчинтэй бүртгэл биш) 400 (муу хүсэлт) HTTP статусыг буцаана. Хүсэлтийн бие дэх параметрт request.body.parameter_name ашиглан ханддаг.Нэвтрэх бүртгэлийн зохицуулагч нь өгөгдсөн login_name-тэй хэрэглэгч байгаа эсэхийг шалгах ёстой гэдгийг анхаарна уу. Хэрэв тийм бол энэ нь хэрэглэгч нэвтэрсэн эсэхийг мэдэх шаардлагатай бусад хүсэлт боловсруулагчаар шалгах боломжтой зарим мэдээллийг Экспресс сессэд хадгалдаг. POST /admin/login -ийн буцаах хэсэг нь таны нэвтэрсэн хэрэглэгчийн шинж чанар буюу вэб програмын хэрэгцээ байх ёстой. Манай шалгах хэсгүүдэд _id property шаарддаг боловч та бусад хэрэглэгчийн объектын шинж чанаруудыг оруулж болно. 4-р асуудалд нэмсэн зүйлээс болж хэрэглэгчийн объектыг бүхэлд нь буцаах нь дэмий болдог.
  • /admin/logout -Энэ URL руу хоосон биетэй POST хүсэлт нь сессэд (session) хадгалагдсан мэдээллийг устгаснаар хэрэглэгч оролтоос гарах болно. Хэрэглэгч одоогоор нэвтрээгүй байгаа үед HTTP статус 400 (муу хүсэлт) буцаж ирэх ёстой.

Нэвтрэх/гаралтыг зохицуулахын тулд вэб серверийг шинэчлэх нэг хэсэг болгон хэрэв сессийн төлөв нь хэрэглэгч нэвтрээгүй гэвэл чи бүх хүсэлтүүдээ (/admin/login болон /admin/logout-аас бусад) 401 (Unauthorized) статусыг арилгахын тулд дахин шинэчлэх хэрэгтэй.

Даалгавар 2: Шинэ сэтгэгдэл (15 оноо)

Хэрэглэгчийн нэвтрэлтийг хэрэгжүүлсний дараа дараагийн алхам бол зураг дээр сэтгэгдэл нэмэх боломжийг хэрэгжүүлэх явдал юм. Зургийн тайлбарыг харуулах зургийн дэлгэрэнгүй харагдац дээр одоо нэвтэрсэн хэрэглэгчид зурган дээрээ сэтгэгдэл нэмэх боломжийг нэмнэ үү. Та энэ функцийн хэрэглэгчийн интерфэйсийг (жишээ нь, попап харилцах цонх, оруулах талбар гэх мэт) зохион бүтээх хэрэгтэй. Үүнийг хэрхэн ашиглах, ямар зургийн тухай сэтгэгдэл бичих нь тодорхой байх ёстой. Зургийн дэлгэц болон түүний тайлбарыг шинээр нэмсэн сэтгэгдлийг тусгахын тулд нэн даруй шинэчлэх шаардлагатай.

Арын талын дэмжлэгийн хувьд вэб серверийн API-г дараах HTTP POST API-аар өргөтгөнө үү:

  • /commentsOfPhoto/:photo_id - ID нь photo_id гэсэн зурган дээр сэтгэгдэл нэмнэ. POST хүсэлтийн үндсэн хэсэг нь тайлбарын текстийг агуулсан нэг property тайлбар бүхий comment-ийг JSON кодлогдсон бие байлгах ёстой. Зураг дээр үүсгэсэн сэтгэгдэл бичих объект нь нэвтэрсэн хэрэглэгчийн таниулбар болон сэтгэгдэл үүсгэсэн цагийг агуулсан байх ёстой. Таны хэрэгжилт 400 статустай (Bad request) хоосон сэтгэгдэл бичих боломжгүй байлгах ёстой.

Даалгавар 3: Зураг байршуулах (15 оноо)

Хэрэглэгчдэд шинэ зураг нэмэх боломжийг бий болгоно. Хэрэглэгч нэвтэрсэн үед үндсэн хэрэгслийн (toolbar) мөрөнд "Зураг нэмэх" гэсэн товчлуур байх ёстой бөгөөд энэ нь одоогийн нэвтэрсэн хэрэглэгчийг апп руу зураг оруулах боломжийг олгодог. Зургийг амжилттай байршуулсны дараа энэ нь хэрэглэгчийн зургийн хуудсан дээр автоматаар гарч ирэх эсвэл хамгийн багадаа зургийг нэмсэн гэсэн тэмдэгтэй байх ёстой. Бид танд HTML ашиглан файл байршуулах жишээг доорх зөвлөмж(hint) хэсэгт өгөх болно.

URL дэх POST хүсэлтийг дэмжихийн тулд вэб серверийг өргөтгөх нь:

  • /photos/new - Одоо байгаа хэрэглэгчийн зургийг байршуулна уу. POST хүсэлтийн үндсэн хэсэг нь файл байх ёстой (доорх зөвлөмжийг (hints) үзнэ үү). Байршуулсан файлуудыг images ргийн санд өөрийн үүсгэсэн өвөрмөц нэрээр байршуулах ёстой. Өвөрмөц нэрийг үүсгэсэн өгөгдөл болон нэвтэрсэн хэрэглэгчийн ID-ийн хамт таны шинээр үүсгэсэн Фото объектод оруулах ёстой. Хэрэв POST хүсэлтэд файл байхгүй бол 400 гэсэн хариултын статусыг буцаана. Энэ талаар тусламж авахыг хүсвэл зөвлөмж (hints) хэсгээс үзнэ үү.

Даалгавар 4: Бүртгэл ба нууц үг (15 оноо)

Шинэ хэрэглэгчийн бүртгэл болон нууц үгийг дэмжихийн тулд LoginRegister харах бүрэлдэхүүн (view component) хэсгийг сайжруулна уу. Шинэ хэрэглэгчийн бүртгэл болон нууц үгийг дэмжихийн тулд LoginRegister харах бүрэлдэхүүн (view component) хэсгийг сайжруулна уу. Нууц үг оруулах хэсэг нэмэхийн тулд нэвтрэх хэсгийг сунгана уу. Хэрэглэгчийн объектын бүх хэсгийг дүүргэх боломжийг олгодог бүртгэлийн хэсгийг нэмнэ үү. Хэрэглэгч нууц үгээ бичдэг гэсэн магадлалыг багасгахын тулд харагдац нь нууц үгийн хэсгийг дахин хуулбарлан агуулсан байх ёстой бөгөөд харагдац нь зөвхөн хэрэглэгчийн оруулсан нууц үгийн болон хуулбар хоёр талбар ижил байвал үүсгэнэ. Аюулгүй байдлын практик нь хэрэглэгчийн оруулсан нууц үг нь харагдах байдалд харагдахгүй байхыг шаарддаг. Бүртгэлийг хуудасны доод хэсэгт байрлах "Register Me" гэсэн товчлуураар идэвхжүүлнэ. Товчлуур дээр дарахад specifically яагаад ажиллахгүй байгааг тайлбарласан алдааг харуулах эсвэл амжилттай болсон тухай мэдээлэл ба бүртгэлийн маягтын оруулах талбаруудыг арилгах шаардлагатай.

Backend-ийн хувьд User ийн объектын схемийг нууц үг хадгалах password бүхий мөрийн талбарыг өргөтгө. Энэ бол үнэхээр найдваргүй зүйл. Хэрэв та маш их найдваргүй зүйлийг хэрэгжүүлмээргүй бол доорх Нэмэлт кредитийг харна уу.

URL руу POST хүсэлтийг дэмжихийн тулд вэб серверийг өргөтгөх нь :
  • /user - Хэрэглэгч бүртгүүлэх боломжийг олгоно. Бүртгэлийн POST нь дараах шинж чанаруудтай JSON кодлогдсон биеийг авдаг: (login_name, password, first_name, last_name, location, description, occupation). Нийтлэлийн хүсэлтийг зохицуулагч нь шинэ login_name зааж өгсөн бөгөөд аль хэдийн байхгүй эсэхийг шалгах ёстой. first_name, last_name, болон password нь хоосон биш мөр байх ёстой (бусад талбарууд хоосон байж болно). Хэрэв мэдээлэл хүчинтэй бол өгөгдлийн санд шинэ хэрэглэгч бий болно. Хариултын хэсэг нь таны вэб програмд ​​хэрэгтэй шинж чанарууд байх ёстой. Манай тестүүд login_name шинж чанарыг агуулсан байхыг шаарддаг. Хэрэв алдаа гарсан бол хариу нь 400 статус болон алдааг харуулсан мөрийг буцаана.

Нууц үгээр нэвтрэхийг дэмжихийн тулд LoginRegister харагдацыг сайжруулж, /admin/login руу илгээх хүсэлтийн нэг хэсэг болгон шалгана уу.

Нэмэлт оноо #1: Давсалсан нууц үг (5 оноо)

Давслах аргыгsalting хэрэгжүүлснээр нууц үгийнхээ механизмын аюулгүй байдлыг сайжруулаарай. The salting mechanism is described in the next few paragraphs. Давслах механизмыг дараагийн хэдэн догол мөрөнд тайлбарласан болно. 4-р даалгаварт бидний хэрэгжүүлсэн тодорхой текст нууц үгийн механизмтай холбоотой даалгавар нь хэн нэгэн өгөгдлийн санд уншиж чаддаг бол (жишээлбэл, системийн администратор гэх мэт) бүх хэрэглэгчийн нууц үгийг хялбархан олж авах боломжтой.

Нууц үг болгонд SHA-1 гэх мэт мессежийг нэгтгэх функцийг хэрэглэж, өгөгдлийн санд зөвхөн мессежийн нэгтгэлийг хадгалах нь илүү сайн арга юм. SHA-1 нь нууц үг гэх мэт мөрийг оролт болгон авч, 40 тэмдэгтээс бүрдэх зургаан өнцөгт цифрүүдийн мөрийг мессежийн дайжест ( message digest гэж нэрлэдэг) гаралт болгон гаргадаг. Гаралт нь хоёр property-той байна: нэгдүгээрт, цифр нь оролтын мөрөнд өвөрмөц гарын үсгийг өгдөг (ижил дайжест-тэй хоёр өөр мөр үүсгэх тодорхой арга байхгүй); Хоёрдугаарт, мессежийн дайжест-ийг өгвөл уг дайжест-ийг үүсгэх мөрийг үүсгэх ямар ч мэдэгдэж байгаа арга байхгүй. Хэрэглэгч нууц үгээ тохируулах үед та Node crypto багцын createHash функцийг ажиллуулж тухайн нууц үгтэй тохирох SHA-1 дайжест үүсгэх ба өгөгдлийн санд зөвхөн дайжест хадгалах ёстой. Үүнийг хийсний дараа та нууц үгээ ашиглахгүй байж болно. Хэрэглэгч нэвтрэхийн тулд нууц үгээ оруулах үед дайжест тооцоолохын тулд createHash функцийг ажиллуулж, мэдээллийн санд хадгалагдаж буй мэдээлэлтэй харьцуулна уу. Энэ аргын тусламжтайгаар та хэрэглэгч нэвтэрч орохдоо нууц үгээ зөв оруулсан эсэхийг шалгах боломжтой боловч хэрэв хэн нэгэн өгөгдлийн сангаас мэдээлэл уншвал тэр мэдээллийг ашиглах боломжгүй.

Гэсэн хэдий ч өмнөх догол мөрийн арга барил нь нэг дутагдалтай хэвээр байх болно. Халдагчид дайжест агуулсан өгөгдлийн сангийн хуулбарыг авсан гэж бодъё. SHA-1 функц нь олон нийтэд нээлттэй байдаг тул тэд энгийн нууц үгийг таахад хурдан толь бичгийн халдлага (fast dictionary attack) ашиглаж болно. Үүнийг хийхийн тулд халдагч үг бүрийг толь бичгээс авч, SHA-1-ийг ашиглан дайжест-ийг тооцоолно. Дараа нь халдагчид өгөгдлийн сан дахь дайжест бүрийг толь бичигт байгаа дижестүүдтэй харьцуулан шалгадаг (үүнийг бүх толь бичгийг хэш хүснэгтэд оруулснаар маш хурдан хийж болно). Хэрэв хэрэглэгч нууц үгээ энгийн толь бичгийн үгийг сонгосон бол халдагч үүнийг хурдан таах боломжтой.

Толь бичгийн довтолгоог илүү төвөгтэй болгохын тулд та нууц үг давслах аргыг ашиглах ёстой. Хэрэглэгч нууц үгээ тохируулах үед SHA-1 дижестийг тооцоолохын өмнө санамсаргүй тоог тооцоолж, нууц үгтэй холбох ба (8 урттай крипто багцын randomBytes функц нь тохирох санамсаргүй тоог буцаана. Санамсаргүй тоог давс(salt) гэнэ . Дараа нь өгөгдлийн санд давс болон дайджестийг хоёуланг нь хадгална уу. Нэвтрэх үед нууц үгээ шалгахдаа өгөгдлийн сангаас давсыг авч, хэрэглэгчийн бичсэн нууц үгтэй холбож, өгөгдлийн сан дахь дайжесттэй харьцуулах зорилгоор энэ мөрийн хураангуйг тооцоолно. Энэ байдлыг ашиглан нэвтрэх өгөгдлийн санд хандсан халдагч нь дээр дурдсан толь бичгийн довтолгоог ашиглах боломжгүй бөгөөд энэ нь халдагч бүх мэдээллийг дахин тооцоолох шаардлагатай болно. Энэ нь толь бичгийн довтолгоог илүү үнэтэй болгодог.

Үүнийг хэрэгжүүлэхийн тулд хэрэглэгчийн схемээс нууц үгийн property-ийг устгаад нууц үгийн шинж чанарыг шинэ хоёр мөрийн шинж чанараар солино: password_digest and salt. Энэ механизмыг ашиглахын тулд хэрэглэгчийн бүртгэлийг шинэчилж, нэвтэрнэ үү.

Та ICSI301password.js нэртэй node модулийн файл үүсгэж, хэрэгжүүлэлтийг бичих хэрэгтэй. Энэ модуль нь дараах хоёр функцийг экспортлох ёстой:

/**
 * Return a salted and hashed password entry from a clear text password.
 * @param {string} clearTextPassword
 * @return {object} passwordEntry where passwordEntry is an object with two
 * string properties:
 *    salt - The salt used for the password.
 *    hash - The sha1 hash of the password and salt.
 */
function makePasswordEntry(clearTextPassword) {
болон
/**
 * Return true if the specified clear text password and salt generates the
 * specified hash.
 * @param {string} hash
 * @param {string} salt
 * @param {string} clearTextPassword
 * @return {boolean}
 */
function doesPasswordMatch(hash, salt, clearTextPassword) {
Бид энэ интерфейсийг шалгадаг Mocha тест test/passwordApiTest.js файлыг өгсөн. Төслөө илгээхээсээ өмнө энэ тестийг давсан эсэхээ шалгана уу. Та package.json файлдаа mocha serverApiTest.js sessionInputApiTest.js passwordApiTest.js скриптүүдийг нэмж өөрчлөөд npm test гэж эдгээр тестийг ажиллуулж болно. Энэ өөрчлөлтийг хийх нь та энэ нэмэлт оноог авна гэсэн үг юм. Мөн loadDatabase.js скриптэд ICSI301password.js файлыг дуудаж өгсөнөөр шинэ хэрэглэгчийн объектуудад шаардлагатай нууц үгийн шинжүүдийг зөв үүсгэхэд ашиглана.

Нэмэлт оноо #2: Хөтөчийг шинэчлэх (5 оноо)

Энэхүү даалгаврын энгийн хэсгүүдэд хялбар болгох үүднээс бид танд програмын сесшний төлөвийг ЖаваСкриптийн санах ойд хадгалахыг зөвшөөрч байна. Хэдийгээр энэ нь хэрэгжилтийг хөнгөвчлөх боловч хөтчийг шинэчлэх нь програмыг хэн нэвтэрсэнийг мартахад хүргэдэг.

Нэвтрэх сесшний дэмжлэгийг нэмэхээс өмнөх шиг хөтчийн шинэчлэлтийг зохицуулахын тулд програмаа өргөтгө. Таны схем нь хэрэглэгчдэд хөтчийг шинэчлэх боловч нэвтэрсэн хэвээр байх боломжийг олгох ёстой. Та хүссэн хэрэгжүүлэх арга техникээ чөлөөтэй ашиглаж болно, гэхдээ тэдгээр нь:

  • Энэ даалгаврын бусад хэсгүүд, түүний дотор Mocha тестүүдтэй хоцрогдсон нийцтэй байдлыг хадгалах.
  • Програмын аюулгүй байдлыг алдагдуулахгүй байх.
  • Ангийн даалгавар илгээх механизмыг ашиглан ирүүлсэн тохиолдолд ажиллана.

Загварын оноо (5 оноо)

Хэрэв даалгаврын шийдэл нь MVC зохион байгуулалттай, програм хангамжийн стекийн дүрмийг дагаж мөрддөг, ESLINT-ийн анхааруулгагүй ЖаваСкрипт код байвал эдгээр оноог олгоно. Нэмж дурдахад, таны код, загварууд нь цэвэрхэн, уншихад хялбар байх ёстой бөгөөд таны вэб хуудаснууд гадаад төрх, тав тухтай байдлын хувьд дор хаяж "боломжийн сайхан" байх ёстой.

Тест

Тестийн хувьд бид:

  • Шинэ API дуудлагын зарим тестийн хамрах хүрээг хангадаг test/sessionInputApiTest.js нэртэй шинэ тест файлыг өгөх.
  • Одоо байгаа test/serverApiTest.js шинэчилж хэрэглэгч рүү нэвтэрч, API дуудлага бүр дээр сессийн мэдээллийг өгнө.
Бидний шинэчлэлт нь serverApiTest.js файлыг дарж бичих тул нэмэлт зээлийн нэг хэсэг болгон Төсөл 6-д нэмсэн аливаа өөрчлөлтийг буцааж мэдээлэх шаардлагатай болно. Нөөц дамжуулахад туслахын тулд (эсвэл та зүгээр л сонирхож байгаа бол) бид HTTP хүсэлтийн дуудлага бүрийн хүсэлтийн сонголтуудад күүки толгойн түлхүүр-утгийн хосыг нэмсэн гэдгийг анхаарна уу. Дэлгэрэнгүйг тестийн файлаас үзнэ үү.

Төсөл 6-д байгаа шиг, шалгалт өгөхөөсөө өмнө өгсөн шалгалтуудыг заавал давах хэрэгтэй, учир нь таны үнэлгээний тодорхой хэсэг нь эдгээр шалгалтын хэд нь тэнцсэнээс хамаарна.

Туршилтууд нь өгөгдлийн санд зөвхөн loadDatabase.js бъектуудыг агуулж байгааг анхаарна уу. Та тестийг эхлүүлэхийн өмнө loadDatabase.js ажиллуулах хэрэгтэй.

Ямар нэгэн тест хийхээсээ өмнө project7/test directory-д npm install командыг бичиж test/node_modules шинэчлэгдсэн эсэхийг шалгах хэрэгтэй.

You Та 2 багцыг хуучирсан тухай анхааруулга авч магадгүй (жишээ нь request болон har-validator). Эдгээр нь бидний туршилтад ашигладаг номын сангийн аль нэг нь засвар үйлчилгээ хийж байгаатай холбоотой сэрэмжлүүлэг тул та эдгээрийг үл тоомсорлож болно. Та өмнөх шигээ npm run test командыг ашиглан тестүүдийг ажиллуулж болно.

Зөвлөмж

Та одоо MongoDB өгөгдлийн санг шинэчлэх код бичиж байгаа тул таны кодын алдаа нь өгөгдлийн сангийн агуулгыг гэмтээж болзошгүй юм. loadDatabase.js програмыг дахин ажиллуулснаар таны өгөгдлийн санг цэвэр төлөвт(clean state) дахин тохируулна. Туршилтууд таныг run бүрийн өмнө үүнийг хийсэн гэж үздэг.

Даалгавар 1

Энэ асуудал нь таныг React програм болон вэб серверт нэвтэрсэн хэрэглэгчийн тухай ойлголтыг авахыг шаарддаг. Та өөрийн апп-аас вэб сервер рүү POST хүсэлт үүсгэхийн тулд загвараа буулгаж, сессийн төлөвийг тохируулах хэрэгтэй. Сервер талын функцэд та үүний эсрэг ажиллуулж болох тестүүд байдаг.

Хэрэв та өөрийн LoginRegister cбүрэлдэхүүн хэсгийг бичиж, зургийн програмдаа нэмээд "/login-register" зам руу чиглүүлсэн гэж үзвэл бид хэрэглэгч нэвтэрч ороогүй тохиолдолд тухайн харагдацыг харуулах хэрэгтэй. React React Router нь ашигтай үйлчилгээ үзүүлдэг. Дахин чиглүүлэлттэй ажиллах арга: React Router Redirect. Хэрэв хэрэглэгч нэвтэрч ороогүй бол /login-register руу дахин чиглүүлэхийн тулд та маршрутаа өөрчилж болно. Жишээлбэл, хэрэв танд дараах маршрут байгаа бол:

<Route path="/users/:id" component={UserDetail} />
болонthis.userIsLoggedIn, бүрэлдэхүүн хэсгийн өмчийг та дараах нөхцөлөөр багцалж /login-register руу шилжүүлж болно:
{
  this.userIsLoggedIn ?
    <Route path="/users/:id" component={UserDetail} />
    :
    <Redirect path="/users/:id" to="/login-register" />
}

Даалгавар 4 нь таны 1-р асуудалд зориулж бичсэн кодыг сайжруулдаг тул та Асуудлын 1-ийн шийдлийг бүтээхээсээ өмнө түүний хэрэгцээг ойлгохыг хүсч болно.

Даалгавар 2

Энэ асуудал нь 1-р асуудлыг шийдэхэд шаардлагатай ихэнх зүйлийг дахин ашиглах болно. Нэг ялгаа нь comment нь манай схемийн бие даасан объект биш юм. Тэдгээрийг фото объект дотор суулгасан тул та объект үүсгэхийн оронд объектын шинэчлэлт хийх шаардлагатай болно.

Даалгавар 3

Хөтөчүүд JavaScript кодыг дурын файлуудыг уншихыг хүсэхгүй байгаа тул JavaScript фреймворкуудад файл байршуулах нь хэцүү байдаг. Хөтөчүүд нь хэрэглэгчдэд файлаа сонгоод агуулгыг нь вэб серверт илгээх боломжийг олгодог интерфейсээр хангадаг. Бид энэ механизмыг ашиглан манай зургийн аппликейшнд зураг байршуулах боломжтой.

React нь HTML-ийн input with type="file" ашиглан хэрэглэгчдэд файл сонгох боломжийг бий болгоно. Дараах мөрийг таны зургийн аппликейшн дээр нэмсэн

<input type="file" accept="image/*" ref={(domFileRef) => { this.uploadInput = domFileRef; }} />
нь хөтөчийг(Browser) "Choose File" гэсэн хэсэгтэй товчлуурыг нэмж оруулах бөгөөд хэрэглэгч дотоод файлаа сонгох боломжтой. Хэрэглэгч файлыг сонгох үед this.uploadInput нь DOM файлыг авч вэб сервер рүү илгээх боломжтой оролтын элементээс DOM FileList агуулна. Та мөн доор тайлбарласны дагуу фото файлыг серверт илгээхийн тулд хэрэглэгч дарах товчлууртай байх шаардлагатай.

Сонгосон файлыг DOM-д оруулсны дараа бид үүнийг DOM form нэмж, вэб сервер рүү POST хүсэлтээр илгээх боломжтой. Дараах код нь үүнийг хийх жишээг өгдөг. Энэ нь оролтын элементийн DOM файлын жагсаалтыг this.uploadInput-д оруулсан гэж үздэг.

/**
 * Called when user presses the update button.
 */
handleUploadButtonClicked = (e) => {
  e.preventDefault();
  if (this.uploadInput.files.length > 0) {
    // Create a DOM form and add the file to it under the name uploadedphoto
    const domForm = new FormData();
    domForm.append('uploadedphoto', this.uploadInput.files[0]);
    axios.post('/photos/new', domForm)
      .then((res) => {
        console.log(res);
      })
      .catch(err => console.log(`POST ERR: ${err}`));
  }
}

Body-parser ашиглан экспресс нь файл агуулсан маягттай POST хүсэлтийг зохицуулах боломжгүй боловч multer нэртэй дунд программаар хийх боломжтой. Мультерийн require-ийн дараа дараах мөрийг оруулна уу:

const processFormBody = multer({storage: multer.memoryStorage()}).single('uploadedphoto');
processFormBody нь бидний /photos/new -д зориулсан шуудангийн хүсэлтийг зохицуулагчдаа ашиглаж болох функц юм. processFormBody нь "uploadedphoto" нэртэй талбарын маягтыг харж, тэндээс файлыг татаж аваад хүсэлтийн объект дээр file нэртэй өмчийн мэдээллийг байрлуулна. Дараах код нь таны шуудангийн хүсэлтийн зохицуулагч дээр үүнийг хэрхэн дуудах талаар санааг өгнө:
processFormBody(request, response, function (err) {
  if (err || !request.file) {
      // XXX -  Insert error handling code here.
      return;
  }

  // request.file has the following properties of interest:
  //   fieldname    - Should be 'uploadedphoto' since that is what we sent
  //   originalname - The name of the file the user uploaded
  //   mimetype     - The mimetype of the image (e.g., 'image/jpeg',
  //                  'image/png')
  //   buffer       - A node Buffer containing the contents of the file
  //   size         - The size of the file in bytes

  // XXX - Do some validation here.

  // We need to create the file in the directory "images" under an unique name.
  // We make the original file name unique by adding a unique prefix with a
  // timestamp.
  const timestamp = new Date().valueOf();
  const filename = 'U' +  String(timestamp) + request.file.originalname;

  fs.writeFile("./images/" + filename, request.file.buffer, function (err) {
    // XXX - Once you have the file written into your images directory under the
    // name filename you can create the Photo object in the database
  });
});

Дээрх кодын фрагмент нь Node.js багц fs-г ашигладаг тул та үүнийг webServer.js-дээ оруулах хэрэгтэй болно:

const fs = require("fs");

Даалгавар 4

Энэ асуудал нь өмнөх асуудлуудад шаардлагатай арга техникийг нэгтгэсэн болно.

Хүлээлгэн өгөх үр дүн

project7 илгээхдээ стандарт submission mechanism-ийг ашиглана. Please clean up your project directory Илгээх зааварт заасны дагуу илгээхээсээ өмнө төслийн лавлахаа (directory) цэвэрлэнэ үү. Нэмж дурдахад, зургийн лавлахдаа байршуулсан бүх зургийг устгана уу. Хэрэв та "Зөвлөгөө (Hint)" хэсэгт байршуулсан зургуудыг нэрлэх дүрмийг баримталсан бол rm -f images/U* командыг ашиглан project7-аас устгаж болно.