著者:しょっさん
プログラミング言語「JavaScript」の実行環境「Node.js」と「Express」フレームワークを使って、基本となるWebアプリの開発手法を習得しましょう。第4回は「蔵書管理アプリケーション」のサンプルプログラムで認証機能を実現す
る方法を解説します。
シェルスクリプトマガジン Vol.58は以下のリンク先でご購入できます。
1 2 3 4 5 |
user.associate = function (models) { // associations can be defined here user.hasMany(models.Library, { foreignKey: 'user_id' }); }; return user;return user; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
'use strict'; module.exports = (sequelize, DataTypes) => { var Library = sequelize.define('Library', { book_title: DataTypes.STRING, author: DataTypes.STRING, publisher: DataTypes.STRING, image_url: DataTypes.STRING(2048), user_id: DataTypes.INTEGER }, { underscored: true }); Library.associate = function (models) { // associations can be defined here Library.hasMany(models.Comment, { foreignKey: 'book_id'}); }; return Library; }; |
1 2 3 4 5 6 7 8 9 10 11 |
user_id: { type: Sequelize.INTEGER, allowNull: false, foreignKey: true, references: { model: 'users', key: 'id', }, onUpdate: 'RESTRICT', onDelete: 'RESTRICT', }, |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
'use strict'; module.exports = { up: (queryInterface, Sequelize) => { const models = require('../models'); return models.user.bulkCreate([ { id: 1, email: 'tak@oshiire.to', password: '$2b$10$t73WMpPlvyhkWuL.ALWe..OKbU1q1ssR4K5ezVTXLlvaDMtUuAqve', salt: '$2b$10$t73WMpPlvyhkWuL.ALWe..' }, { id: 2, email: 'sho@oshiire.to', password: '$2b$10$t73WMpPlvyhkWuL.ALWe..OKbU1q1ssR4K5ezVTXLlvaDMtUuAqve', salt: '$2b$10$t73WMpPlvyhkWuL.ALWe..' }, { id: 3, email: 'shosan@oshiire.to', password: '$2b$10$t73WMpPlvyhkWuL.ALWe..OKbU1q1ssR4K5ezVTXLlvaDMtUuAqve', salt: '$2b$10$t73WMpPlvyhkWuL.ALWe..' } ]); }, down: (queryInterface, Sequelize) => { return queryInterface.bulkDelete('users', null, {}); } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; const hashPassword = (password, salt) => { var bcrypt = require('bcrypt'); var hashed = bcrypt.hashSync(password, salt); return hashed; }; passport.use(new LocalStrategy( { usernameField: 'email', passwordField: 'password' }, (username, password, done) => { models.user.findOne({ where: { email: username } }).then(user => { if (!user) return done(null, false, { message: 'Incorrect email.' }); if (hashPassword(password, user.salt) !== user.password) return done(null, false, { message: 'Incorrect password.' }); return done(null, user.get()); }); } )); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var session = require('express-session'); passport.serializeUser((user, done) => { done(null, user.id); }); passport.deserializeUser((id, done) => { models.user.findById(id).then(user => { if (user) { done(null, user.get()); } else { done(user.errors, null); } }); }); |
1 2 3 4 5 6 7 8 9 10 |
app.use((req, res, next) => { if (req.isAuthenticated()) return next(); if (req.url === '/' || req.url === '/login') return next(); res.redirect('/'); }); app.use('/', index); app.use('/books', books); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* eslint-env jasmine */ // routing テスト const request = require('supertest-session'); const app = require('../app'); //let's set up the data we need to pass to the login method const userCredentials = { email: 'tak@oshiire.to', password: 'password' }; const wrongEmailCredentials = { email: 'foo', password: 'password' }; const wrongPasswordCredentials = { email: 'tak@oshiire.to', password: 'foo' }; //now let's login the user before we run any tests const authenticatedUser = request(app); describe('POST /login', () => { it('should redirect to / with unloggined user', (done) => { request(app) .get('/books/') .expect(302) .expect('Location', '/', done); }); it('should success login with correct user', (done) => { request(app) .post('/login') .send(userCredentials) .expect(302) .expect('Location', '/books/', done); }); it('should deny login with wrong email', (done) => { request(app) .post('/login') .send(wrongEmailCredentials) .expect(302) .expect('Location', '/', done); }); it('should deny login with wrong password', (done) => { request(app) .post('/login') .send(wrongPasswordCredentials) .expect(302) .expect('Location', '/', done); }); }); describe('with Login', () => { beforeAll((done) => { authenticatedUser .post('/login') .send(userCredentials) .expect(302, done); }); describe('GET /', () => { it('respond with http', (done) => { authenticatedUser .get('/') .set('Accept', 'text/html') .expect(200, done); }); }); : (中略) : }); describe('GET /logout', () => { beforeAll((done) => { authenticatedUser .post('/login') .send(userCredentials) .expect(302, done); }); it('should go back to login', (done) => { authenticatedUser .get('/logout') .set('Accept', 'text/html') .expect(302) .expect('Location', '/', done); }); }); |