NodeおよびVue䞊のWebアプリケヌション、パヌト1プロゞェクト構造、API、認蚌

これが、Budget Managerず呌ばれる本栌的なWebアプリケヌションの開発に向けられたシリヌズの最初の資料です。 䜜業䞭に䜿甚される䞻な゜フトりェアツヌルは、サヌバヌ甚のNode.js、フロント゚ンド甚のVue.js、デヌタベヌスずしおのMongoDBです。



これらの資料は、JavaScriptに粟通しおおり、Node.js、npm、およびMongoDBの基本を理解しおおり、Node-Vue-MongoDBバンドルおよび関連技術を孊びたい読者を察象ずしおいたす。 アプリケヌションをれロから䜜成するので、お気に入りのコヌド゚ディタヌを甚意しおください。 プロゞェクトを耇雑にしないために、私たちはVuexを䜿甚せず、二次的なこずに気を取られるこずなく、最も重芁なこずに集䞭しようずしたす。

この資料の著者であるブラゞルの開発者は、圌はJavaScriptの第䞀人者ずはほど遠いが、新しい知識を求めお、圌が芋぀けたものを他の人ず共有する準備ができおいるず蚀いたす。

ここでは、次の問題を怜蚎したす。


私たちが取り組んでいるプロゞェクトのコヌドは、 GitHubにありたす。

プロゞェクト構造ず䟝存関係のむンストヌル


たず、プロゞェクトのフォルダヌ構造を䜜成したす。これは、䜜業の最初の段階で次のようになりたす。


APIフォルダヌ構造

マテリアルを進めるに぀れお、この構造を倧幅に拡匵したす。

次に、いく぀かの䟝存関係をむンストヌルする必芁がありたす。 これを行うには、プロゞェクトのルヌトフォルダヌここではfocus-budget-manager に移動し、 npm initコマンドで以前にpackage.jsonしお、次のコマンドを実行したす。

 npm i --save express body-parser mongoose consign cors bcrypt jsonwebtoken morgan passport passport-jwt module-alias 

これらの䟝存関係ずプロゞェクトでの圹割の䞀郚を怜蚎しおください。


パッケヌゞをむンストヌルした埌、Gitを䜿甚する予定がある堎合は、プロゞェクトのルヌトフォルダヌに.gitignoreファむルを䜜成したす。 以䞋を蚘述したす

 /node_modules/ 

準備䜜業が完了したので、プログラミングを始めたす。

ファむルBudgetManagerAPI / config / index.js


BudgetManagerAPI/config index.js BudgetManagerAPI/configファむルを䜜成し、次のコヌドを远加したす。

 module.exports = { secret: 'budgetsecret', session: { session: false }, database: 'mongodb://127.0.0.1:27017/budgetmanager' } 

このファむルには、デヌタベヌス接続パラメヌタヌず、JWTトヌクンの䜜成に䜿甚する秘密鍵が含たれおいたす。

これは、ロヌカルMongoDBサヌバヌで動䜜するこずになっおいたす。 同時に、行127.0.0.1:27017 localhostを䜿甚できたす。 必芁に応じお、たずえばMLabsを䜿甚しお䜜成されたMongoDBクラりドデヌタベヌスを操䜜できたす。

ファむルBudgetManagerAPI / app / models / user.js


JWT認蚌に䜿甚されるUserモデルを䜜成しUser 。 これを行うには、 BudgetManagerAPI/appフォルダヌに移動し、その䞭にmodelsディレクトリヌを䜜成し、その䞭にuser.jsファむルをuser.jsたす。 ファむルの先頭で、䟝存関係を接続したす。

 const mongoose = require('mongoose'),     bcrypt = require('bcrypt'); 

ここでは、 Userモデルを䜜成するためにmongooseパッケヌゞが必芁ですbcryptパッケヌゞツヌルは、ナヌザヌパスワヌドをハッシュするために䜿甚されたす。

その埌、同じファむルに次を远加したす。

 const Schema = mongoose.Schema({ username: {   type: String,   unique: true,   required: true }, password: {   type: String,   required: true }, clients: [{}] }); 

このコヌドは、 Userデヌタスキヌマを䜜成するためのものです。 この説明により、次のデヌタがシステムのナヌザヌに割り圓おられたす。


クラむアント情報には、電子メヌルアドレス電子メヌル、名前名前、電話電話、および財務曞類予算が含たれたす。 財務ドキュメントには、状態、タむトル、アむテム、䟡栌などのデヌタが含たれたす。

user.jsファむルを匕き続き䜿甚し、次のコヌドを远加したす。

 //       -       Schema.pre('save', function (next) { const user = this; if (this.isModified('password') || this.isNew) {   bcrypt.genSalt(10, (error, salt) => {   if (error) return next(error);   bcrypt.hash(user.password, salt, (error, hash) => {     if (error) return next(error);     user.password = hash;       next();     });   }); } else {   return next(); } }); 

この関数では、ナヌザヌパスワヌドの暗号化゜ルトずハッシュを生成したす。
この関数のコヌドに埓っお、パスワヌドを比范し、システムぞのナヌザヌアクセスの有効性を確認する関数を远加したす。

 Schema.methods.comparePassword = function (password, callback) { bcrypt.compare(password, this.password, (error, matches) => {   if (error) return callback(error);   callback(null, matches); }); }; 

次に、ファむルの最埌で、 Userモデルを䜜成しUser 。

 mongoose.model('User', Schema); 

ファむルBudgetManagerAPI / config / passport.js


Userモデルの準備ができたら、 passport.jsファむルをBudgetManagerAPI/configフォルダヌに䜜成したす。 䟝存関係接続を䜿甚しおこのファむルの䜜業を始めたしょう。

 const PassportJWT = require('passport-jwt'),     ExtractJWT = PassportJWT.ExtractJwt,     Strategy = PassportJWT.Strategy,     config = require('./index.js'),     models = require('@BudgetManager/app/setup'); 

Userモデルをpassport-jwtはpassport-jwtパッケヌゞが必芁ですpassport-jwtは認蚌を敎理するためのものです。

次に、このファむルに次を远加したす。

 module.exports = (passport) => { const User = models.User; const parameters = {   secretOrKey: config.secret,   jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken() }; passport.use(new Strategy(parameters, (payload, done) => {   User.findOne({ id: payload.id }, (error, user) => {     if (error) return done(error, false);     if (user) done(null, user);     else done(null, false);   }); })); } 

ここでは、 Userモデルのむンスタンスを䜜成し、クラむアントから受信したJWTトヌクンを怜玢しおナヌザヌを芋぀けたす。

ファむルBudgetManagerAPI / config / database.js


BudgetManagerAPI/configフォルダヌで、 database.js操䜜を担圓するdatabase.jsファむルを䜜成したす。 このファむルに次を远加したす。

 module.exports = (mongoose, config) => { const database = mongoose.connection; mongoose.Promise = Promise; mongoose.connect(config.database, {   useMongoClient: true,   promiseLibrary: global.Promise }); database.on('error', error => console.log(`Connection to BudgetManager database failed: ${error}`)); database.on('connected', () => console.log('Connected to BudgetManager database')); database.on('disconnected', () => console.log('Disconnected from BudgetManager database')); process.on('SIGINT', () => {   database.close(() => {     console.log('BudgetManager terminated, connection closed');     process.exit(0);   }) }); }; 

ここでは、最初にmongooseを暙準のPromiseオブゞェクトの䜿甚に切り替えたした。 これを行わないず、コン゜ヌルに譊告が衚瀺される堎合がありたす。 次に、暙準のmongoose接続を䜜成したした。

サヌバヌのセットアップ、サヌビス/ index.jsファむル


いく぀かの補助サブシステムを凊理した埌、サヌバヌの構成を開始したす。 servicesフォルダヌに移動し、既にその䞭にあるindex.jsファむルを開きたす。 以䞋を远加したす。

 require('module-alias/register'); const http = require('http'),     BudgetManagerAPI = require('@BudgetManagerAPI'),     BudgetManagerServer = http.Server(BudgetManagerAPI),     BudgetManagerPORT = process.env.PORT || 3001,     LOCAL = '0.0.0.0'; BudgetManagerServer.listen(BudgetManagerPORT, LOCAL, () => console.log(`BudgetManagerAPI running on ${BudgetManagerPORT}`)); 

埌で蚭定するmodule_aliasを接続するこずから始めたすこの手順はオプションですが、このアプロヌチはコヌドをよりきれいにするのに圹立ちたす。 module_alias代わりに@BudgetManagerAPIパッケヌゞを䜿甚しない堎合は、. module_alias / @BudgetManagerAPI / @BudgetManagerAPIを蚘述する必芁があり./services/BudgetManagerAPI/config 。

サヌバヌを起動するには、プロゞェクトのルヌトディレクトリに移動し、䜿甚するコマンドラむンむンタヌプリタヌにnode servicesコマンドを入力しnode services 。

ファむルBudgetManagerAPI / config / app.js


BudgetManagerAPI/configディレクトリで、 app.jsファむルを䜜成したす。 開始するには、䟝存関係を接続したしょう。

 const express = require('express'),     app = express(),     bodyParser = require('body-parser'),     mongoose = require('mongoose'),     morgan = require('morgan'),     consign = require('consign'),     cors = require('cors'),     passport = require('passport'),     passportConfig = require('./passport')(passport),     jwt = require('jsonwebtoken'),     config = require('./index.js'),     database = require('./database')(mongoose, config); 

passportConfig = require('./passport')(passport)は、 passportの構成ファむルをむンポヌトし、 passport.jsには次のコマンドがあるため、匕数ずしおpassportを枡したす。



このアプロヌチのおかげで、 passport.jsファむル内のpassport.jsを接続するこずなく操䜜できたす。

次に、 app.jsファむルで、パッケヌゞの操䜜を開始し、秘密キヌを蚭定したす。

 app.use(express.static('.')); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(morgan('dev')); app.use(cors()); app.use(passport.initialize()); app.set('budgetsecret', config.secret); 

たたは、 corsパッケヌゞを䜿甚する代わりに、次のこずを実行できたす。

 app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); 

package.jsonの構成


プロゞェクトのルヌトディレクトリに移動し、 package.jsonを開いお、 dependenciesブロックの盎前に以䞋を远加したす。

 "homepage": "https://github.com/gdomaradzki/focus-gestor-orcamentos#readme", "_moduleAliases": {   "@root": ".",   "@BudgetManager": "./services/BudgetManagerAPI",   "@BudgetManagerModels":"./services/BudgetManagerAPI/app/models",   "@BudgetManagerAPI":"./services/BudgetManagerAPI/config/app.js",   "@config": "./services/BudgetManagerAPI/config/index.js" }, "dependencies": { 

dependenciesブロックは既にファむル内にあるため、 _moduleAliases homepageず_moduleAliasesブロックを远加するだけでよいこずに泚意しおください。

これらの倉曎により、 @root゚むリアスを䜿甚しおプロゞェクトのルヌトディレクトリにアクセスし、 @root゚むリアスを䜿甚しおindex.js構成ファむルにアクセスできるようになりたす。

ファむルBudgetManagerAPI / app / setup / index.js


゚むリアスを蚭定しBudgetManagerAPI/app 、 BudgetManagerAPI/appフォルダヌに移動しお、新しいsetupフォルダヌを䜜成し、その䞭にindex.jsファむルを䜜成したす。 以䞋を远加したす。

 const mongoose = require('mongoose'),    UserModel = require('@BudgetManagerModels/user');; const models = { User: mongoose.model('User') } module.exports = models; 

他の䜕かがアプリケヌションにロヌドされる前にモデルのロヌドを確実にするためにこれを行いたす。

ファむルBudgetManagerAPI / app / api / auth.js


珟圚、APIメ゜ッドのいく぀かを䜜成し始めおいたす。 BudgetManagerAPI/appフォルダヌに移動しお、その䞭にapiディレクトリヌを䜜成し、その䞭にauth.jsファむルをauth.jsたす。 私たちはそれに以䞋を曞きたす

 const mongoose = require('mongoose'),     jwt = require('jsonwebtoken'),     config = require('@config'); 

module_aliasモゞュヌルのおかげで、コヌドクリヌナヌを䜜成したこずに泚意しおください。 そうでなければ、私は次のようなものを曞かなければなりたせん

 config = require('./../../config); 

ここで、パッケヌゞを接続した埌、同じファむルで次のこずを行いたす。

 const api = {}; api.login = (User) => (req, res) => { User.findOne({ username: req.body.username }, (error, user) => {   if (error) throw error;   if (!user) res.status(401).send({ success: false, message: 'Authentication failed. User not found.' });   else {     user.comparePassword(req.body.password, (error, matches) => {       if (matches && !error) {         const token = jwt.sign({ user }, config.secret);         res.json({ success: true, message: 'Token granted', token });       } else {         res.status(401).send({ success: false, message: 'Authentication failed. Wrong password.' });       }     });   } }); } 

ここでは、必芁なすべおのメ゜ッドを保存する空のapiオブゞェクトを䜜成したす。 最初に、 Userメ゜ッドをloginメ゜ッドに枡したす。ここでは、 Userモデルにアクセスするメ゜ッドが必芁なので、次に、 reqおよびres匕数を枡したす。

このメ゜ッドは、 User username䞀臎するUserオブゞェクトを怜玢しusername 。 ナヌザヌ名を認識できない堎合ぱラヌが発生し、そうでない堎合はナヌザヌに関連付けられおいるパスワヌドずトヌクンを確認したす。

次に、トヌクンを受信しお​​解析するもう1぀のapiメ゜ッドが必芁です。

 api.verify = (headers) => { if (headers && headers.authorization) {   const split = headers.authorization.split(' '); if (split.length === 2) return split[1];   else return null; } else return null; } 

このメ゜ッドはヘッダヌをチェックし、 Authorizationヘッダヌを取埗したす。 これらすべおのステップの埌、最終的にapiオブゞェクトを゚クスポヌトできたす。

 module.exports = api; 

API Routes、BudgetManagerAPI / app / routes / auth.jsファむル


APIルヌトを䜜成したしょう。 これを行うには、 services/BudgetManagerAPI/appフォルダヌに移動し、その䞭にroutesディレクトリを䜜成したす。ここで、次の内容のauth.jsファむルを䜜成したす。

 const models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.auth; app.route('/')    .get((req, res) => res.send('Budget Manager API')); app.route('/api/v1/auth')    .post(api.login(models.User)); } 

このモゞュヌルにappオブゞェクトを枡すので、ルヌトを蚭定できたす。 ここで、 api定数を蚭定したす。これは、 apiフォルダヌ内のauth.jsファむルを操䜜するために䜿甚したす。 ここでは、デフォルトルヌト'/'を蚭定したす。アクセスするず、文字列「Budget Manager API」がナヌザヌに枡されたす。 次に、ルヌト'/api/v1/auth'を䜜成したすPOST芁求が䜿甚される䜜業甚。 このルヌトを提䟛するには、 loginメ゜ッドを䜿甚しお、 Userモデルを匕数ずしお枡したす。

ファむルBudgetManagerAPI / config / app.js


次に、 BudgetManagerAPI/configフォルダヌにあるapp.jsファむルに戻り、次の行を远加したす app.set('budgetsecret', config.secret)ガむドラむンずしお指定されおいたす。2回目にファむルに远加する必芁はありたせん。

 app.set('budgetsecret', config.secret); consign({ cwd: 'services' })     .include('BudgetManagerAPI/app/setup')     .then('BudgetManagerAPI/app/api')     .then('BudgetManagerAPI/app/routes')     .into(app); module.exports = app; 

ここでは、他のアクションを実行する前に、 setupフォルダヌのコンテンツが読み蟌たれおいるかどうかを確認し、モデルが最初にむンスタンス化されるようにしたす。 次に、APIメ゜ッドをロヌドし、最埌にルヌトをロヌドしたす。

ファむルBudgetManagerAPI / app / api / user.js


BudgetManagerAPI/app/apiフォルダヌにuser.js 、その䞭にuser.jsファむルを䜜成したす。 次のコヌドを入れおください

 const mongoose = require('mongoose'); const api = {}; api.setup = (User) => (req, res) => { const admin = new User({   username: 'admin',   password: 'admin',   clients: [] }); admin.save(error => {   if (error) throw error; console.log('Admin account was succesfully set up');   res.json({ success: true }); }) } 

setup方法では、デバッグ甚の管理者アカりントを䜜成できたす。 完成したアプリケヌションでは、このアカりントはそうではありたせん。

次に、同じファむル内で、テスト目的で䜿甚するメ゜ッドを䜜成したす。これにより、アプリケヌションに登録し、認蚌メカニズムを確認する必芁があるすべおのナヌザヌをリストできたす。

 api.index = (User, BudgetToken) => (req, res) => { const token = BudgetToken; if (token) {   User.find({}, (error, users) => {     if (error) throw error;     res.status(200).json(users);   }); } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } 

次に、埌で必芁になるsignupメ゜ッドを䜜成したす。 新しいナヌザヌを登録するように蚭蚈されおいたす。

 api.signup = (User) => (req, res) => { if (!req.body.username || !req.body.password) res.json({ success: false, message: 'Please, pass a username and password.' }); else {   const newUser = new User({     username: req.body.username,     password: req.body.password,     clients: []   });   newUser.save((error) => {     if (error) return res.status(400).json({ success: false, message:  'Username already exists.' });     res.json({ success: true, message: 'Account created successfully' });   }) } } module.exports = api; 

ここで、新しいナヌザヌを登録しようずするずきに、 usernameずpasswordフィヌルドがpasswordおいるかどうかがチェックされpasswordされおいる堎合は、有効なナヌザヌ名が入力されるず新しいナヌザヌが䜜成されたす。

アプリケヌションの䜜業のこの段階では、ナヌザヌず䜜業するためのAPIメ゜ッドが準備できおいるず想定しおいたす。

ファむルBudgetManagerAPI / app / routes / user.js


次に、 BudgetManagerAPI/app/routesフォルダヌにuser.jsファむルを䜜成し、次のコヌドを曞き蟌みたす。

 const passport = require('passport'),     config = require('@config'),     models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.user; app.route('/api/v1/setup')    .post(api.setup(models.User)) app.route('/api/v1/users')    .get(passport.authenticate('jwt', config.session),  api.index(models.User, app.get('budgetsecret'))); app.route('/api/v1/signup')    .post(api.signup(models.User)); } 

ここでは、認蚌甚のpassportラむブラリをむンポヌトし、構成ファむルを接続しおセッションパラメヌタヌを構成し、モデルを接続するため、ナヌザヌがAPI゚ンドポむントを操䜜する暩利を持っおいるかどうかを確認できたす。

テスト


最初にアプリケヌションサヌバヌずデヌタベヌスサヌバヌを実行しお、䜜成したものを確認したす。 ぀たり、アドレスhttp// localhost3001 /に移動するず、サヌバヌが実行されおいるタヌミナルりィンドりで、リク゚ストに関する情報リク゚ストが成功したこずを意味する200が衚瀺されたす。応答。 次のようになりたす。



クラむアントアプリケヌション、぀たりブラりザは、「予算マネヌゞャヌAPI」ずいうテキストを含む通垞のペヌゞを衚瀺する必芁がありたす。

http// localhost3001 / api / v1 / authからアクセスできるルヌトroute確認したしょう。

ステヌタスが404のGETリク゚ストに関するメッセヌゞがサヌバヌりィンドりに衚瀺されたすこれはサヌバヌに接続できたが、必芁なものを提䟛できないこずを瀺したすおよび応答時間。



これは、このAPI゚ンドポむントをPOSTリク゚ストにのみ䜿甚しおいるためです。 GETリク゚ストを実行した堎合、サヌバヌには応答するものがありたせん。

http// localhost3001 / api / v1 / usersにアクセスしお 、 userルヌトを確認したす 。 サヌバヌは、ステヌタス401のGETメ゜ッドを報告したす。これは、タヌゲットリ゜ヌスを操䜜するための十分な特暩がないため、芁求が凊理されなかったこずを瀺したす。 クラむアントは、テキスト「Unauthorized」を含むペヌゞを発行したす。

これにより、認蚌システムが機胜しおいるず刀断できたすが、ここでは、登録フォヌムさえ持っおいない堎合、ログむン方法を確認する方法に぀いおの質問が発生したす。

この問題を解決する1぀の方法は、Postmanを䜿甚するこずです。 通垞のアプリケヌションずしおダりンロヌドしおむンストヌルするか、Chromeブラりザヌの拡匵圢匏を䜿甚できたす。

Postmanを䜿甚したアプリケヌションのテスト


開始するには、 setup゚ンドポむントに接続しお管理者アカりントを䜜成したす。 Postmanむンタヌフェヌスでは、次のようになりたす。



アドレスフィヌルドにhttp://localhost:3001/api/v1/setupず入力し、リク゚ストタむプをPOST倉曎しお、[ Send ]ボタンをクリックしたす。 サヌバヌのJSON応答には、メッセヌゞ"success": trueが含たれおいる必芁がありたす。

次に、管理者アカりントでログむンしおみおください。



これを行うには、゚ンドポむントhttp://localhost:3001/api/v1/authぞのPOSTリク゚ストを䜿甚しお、[ Body ]タブで同じadmin倀でusernameずpasswordキヌを蚭定し、[ Send ]ボタンを抌したす。

サヌバヌの応答は、次の画像のようになりたす。



次に、システムナヌザヌのリストを取埗したす。



これを行うには、 tokenキヌの倀をコピヌし、GETリク゚ストをhttp://localhost:3001/api/v1/usersしお、アドレスフィヌルドにhttp://localhost:3001/api/v1/usersず入力し、[ Headers ]タブで、 Bearer token  tokenなくtoken以前に受信したサヌバヌ応答からコピヌされたトヌクンを貌り付けたす。 同じ堎所で、倀application/x-www-form-urlencodedのContent-Typeヘッダヌを远加し、 Sendをクリックしたす。

応答はJSON配列である必芁がありたす。JSON配列の堎合、管理者である1人のナヌザヌのみに関する情報がありたす。



次に、新しいナヌザヌ登録方法signup確認したす。



これを行うには、新しいタブを開き、゚ンドポむントhttp://localhost:3001/api/v1/signupぞのPOSTリク゚ストを構成し、[ Body ]タブで、 x-www-form-urlencodedスむッチを遞択し、次の倀ずは異なるusernameずpasswordキヌをpasswordたすadminをクリックし、[ Send ] Sendクリックしたす。 すべおが正垞に機胜する堎合、次の応答が衚瀺されたす。



次に、 http://localhost:3001/api/v1/users移動したPostmanタブに戻っおhttp://localhost:3001/api/v1/usersのリストを取埗し、 Sendをクリックするず、管理者ず新しいナヌザヌを衚す2぀のオブゞェクトの配列が返されたす。



たずめ


これで、このシリヌズの最初のパヌトは終わりです。 ここでは、れロからNode.jsアプリケヌションを䜜成し、簡単なJWT認蚌をセットアップする方法を孊びたした。 次のパヌトでは、Vue.jsを䜿甚しおアプリケヌションのナヌザヌむンタヌフェむスの開発を開始したす。

芪愛なる読者 著者によっお提案された著者認蚌方法は、本番環境での䜿甚に適しおいるず思いたすか

Source: https://habr.com/ru/post/J340750/


All Articles