メモ：node.js＋Postgres＋Basic認証の例

[前](https://qiita.com/DiveMasakazu/items/cecd5987023f7292665f)

前はテスト用に何も考えないRestサーバを立ててみたが、
認証とDBトランザクションを一応考えてもう少しまともなものにしておく。


## Postgresのプール
[ここ](https://qiita.com/sa9ra4ma/items/cea1abecf3434cbbc08c)を参考にpool.jsを作成してみた

```node.js:pool.js
const { Pool } = require("pg");

const pool = new Pool({
    user: 'postgres',
    host: 'localhost',
    database: 'postgres',
    password: 'password',
    port: 5432,
    max: 2
});

pool.tx = async (cb) => {
    const connection = await pool.connect();
    let res;
    try {
        await connection.query('BEGIN');
        try{
            res = await cb(connection);
            await connection.query('COMMIT');
        } catch(err) {
            await connection.query('ROLLBACK');
            throw err;
        }
    } catch(err) {
        throw err;
    } finally {
        connection.release();
    }
    return res;
}

module.exports = pool;
```

これを利用してexpressを使って実行

```
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const dbpool = require('./pool.js');
const port = 3000;

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

var pgSelect = {
    text: 'SELECT id,name from test where id=$1',
    values: [0],
}

var pgInsert = {
    text: 'INSERT INTO test(id,name) VALUES ($1,$2)',
    values: [0,'sample'],
}

app.get('/', async function(req, res, next){
		let result;
		
		const reqid = req.query.id;
		pgSelect.values = [reqid];
		
		try{
			result = await dbpool.tx(async client => {
				const res1 = await client.query(pgSelect);
				return res1;
			});
		} catch(err) {
			console.error(err);
			res.sendStatus(500);
			return;
		}
		
		res.status(200).json(result.rows);
		
	}
);

app.post('/', async function(req, res, next) {
		let result;
		const reqid = req.body.id;
		const reqname = req.body.name;

		
		pgInsert.values = [reqid,reqname];
		
		try{
			result = await dbpool.tx(async client => {
				const res1 = await client.query(pgInsert);
				return res1;
			});
		} catch(err) {
			console.error(err);
			res.sendStatus(500);
			return;
		}
		
		res.status(200).json(result.rowCount);
	}
);

app.listen(port, () => console.log(`Example app listening on port ${port}!`));
```

## Basic認証

form認証等でpassportを使う場合は以下をインストールする。
npm install passport
npm install passport-local
セッション機能を利用する場合は追加
npm install express-session

basic認証で良い場合はpassport（のpassport-http）でも認証可能だが、
npm install express-basic-auth
を使ってもよい。
ただ、認証方式の差し替えを考えるとpassportにしておく方良さそう。

とりあえずbasic認証の方が準備が楽なので、軽く作ってみる。
npm install passport
npm install passport-http
でモジュールはインストール

書き換えて認証を追加。rest想定なのでセッションはfalse
ハッシュ化はnodeの標準モジュールを利用

```
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const dbpool = require('./pool.js');
const passport = require('passport');
const passportHttp = require('passport-http');
const crypto = require("crypto");
const port = 3000;

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use(passport.initialize());

// せっかくなのでusrテーブルで認証させる(SHA256でハッシュ化)
passport.use(new passportHttp.BasicStrategy(
    async function (username, password, done) {
    	let result;
    	const hashpass = crypto.createHash('sha256').update(password).digest('hex');
		try{
			var usrSelect = {
			    text: 'SELECT pass from usr where usr=$1',
			    values: [username],
			}
			result = await dbpool.tx(async client => {
				const res1 = await client.query(usrSelect);
				return res1;
			});
		} catch(err) {
			console.error(err);
			return done(null, false);
		}
    	
        if(hashpass===result.rows[0].pass){
            // 認証成功
            return done(null,true);
        }else{
            // 認証失敗
            return done(null, false);
        }
    }
));

var pgSelect = {
    text: 'SELECT id,name from test where id=$1',
    values: [0],
}

var pgInsert = {
    text: 'INSERT INTO test(id,name) VALUES ($1,$2)',
    values: [0,'sample'],
}

app.get('/', passport.authenticate('basic', { session: false }), async function(req, res, next){
		let result;
		
		const reqid = req.query.id;
		pgSelect.values = [reqid];
		
		try{
			result = await dbpool.tx(async client => {
				const res1 = await client.query(pgSelect);
				return res1;
			});
		} catch(err) {
			console.error(err);
			res.sendStatus(500);
			return;
		}
		
		res.status(200).json(result.rows);
		
	}
);

app.post('/', passport.authenticate('basic', { session: false }), async function(req, res, next) {
		let result;
		const reqid = req.body.id;
		const reqname = req.body.name;

		
		pgInsert.values = [reqid,reqname];
		
		try{
			result = await dbpool.tx(async client => {
				const res1 = await client.query(pgInsert);
				return res1;
			});
		} catch(err) {
			console.error(err);
			res.sendStatus(500);
			return;
		}
		
		res.status(200).json(result.rowCount);
	}
);

app.listen(port, () => console.log(`Example app listening on port ${port}!`));
```
TypeError: req.logIn is not a function
が出て時間をかなり使ったが、
app.use(passport.initialize());
を入れたら大丈夫になった。。