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を使用してアプリケーションのユーザーインターフェイスの開発を開始します。



親愛なる読者! 著者によって提案された著者認証方法は、本番環境での使用に適していると思いますか?



All Articles