40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

Node.jsのセッション管理をよく理解せずにハマったので振り返り

Node.js + Express でログイン認証機能を実装するというそのものズバリの記事を見つけて、そこの記事中で紹介されている Gistのソースを参考にしたのですが、どうにもうまくいかずに、ハマりました

ハマった要因というか、敗因なんですが、記事をナナメ読みしてて、記事中のMongoというキーワード見て

「ひとまず、Mongoは利用しないのでその部分はパスしてやろう」

と決めたのがどうもまずかったみたいです。。。

そこで、まずは基本となるセッション管理の仕組みについて、順を追って文章にまとめておくことで自分の理解を確認しておこうと思います

まずはサンプルとなるアプリを作成

Node.js+expressで、テンプレートエンジンにJadeを使った構成でアプリを作成します

なお、私の環境ですが

-OS: Mac OS X 10.8.5 - Node.js: 0.10.22

という感じです

mkdir expressSample
express expressSample
cd expressSample
cat package.json
{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.4.7",
    "jade": "*"
  }
}
npm install
jade@1.1.4 node_modules/jade
├── character-parser@1.2.0
├── commander@2.1.0
├── mkdirp@0.3.5
├── monocle@1.1.51 (readdirp@0.2.5)
├── transformers@2.1.0 (promise@2.0.0, css@1.0.8, uglify-js@2.2.5)
├── with@2.0.0 (uglify-js@2.4.0)
└── constantinople@1.0.2 (uglify-js@2.4.9)

express@3.4.7 node_modules/express
├── methods@0.1.0
├── merge-descriptors@0.0.1
├── range-parser@0.0.4
├── cookie-signature@1.0.1
├── fresh@0.2.0
├── debug@0.7.4
├── buffer-crc32@0.2.1
├── cookie@0.1.0
├── mkdirp@0.3.5
├── send@0.1.4 (mime@1.2.11)
├── commander@1.3.2 (keypress@0.1.0)
└── connect@2.12.0 (uid2@0.0.3, pause@0.0.1, qs@0.6.6, bytes@0.2.1, raw-body@1.1.2, batch@0.5.0, negotiator@0.3.0, multiparty@2.2.0)

アプリの作成が完了したら

node app.js

とします。デフォルトでは、3000ポートを使って起動されるのでこんな感じのメッセージが表示されます

Express server listening on port 3000

ブラウザを起動して、http://localhost:3000/ にアクセスすると以下のメッセージが表示されます

f:id:h5y1m141:20140120064315p:plain

エラーメッセージの

「doctype 5is deprecated, you must now usedoctype html`」

とあり、viewsディレクトリ配下のlayout.jadeのDocTypeを変更しろとのことなので以下のように変更

変更前

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content

変更後

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    block content

これで、以下のように意図したようになりました

f:id:h5y1m141:20140120064407p:plain

ログインのフォームの値の受け渡し方法がよくわからなかった

自動的に生成される index.jade を以下のように変更して、ログイン用のフォームを配置してみました

index.jadeのコード

extends layout

block content
  h1= title
  p Welcome to #{title}

    form(action='/login')
      label ログインID:
      input(type='text',name='username',placeholder='username')
      br    
      label パスワード:
      input(type='password',name='password',placeholder='Password')
      br
      label.checkbox.gray ログイン状態を保存

        input(type='checkbox')
        br

      button.btn.btn-primary(type='submit') ログイン

app.jsのコード

上記ログインフォームでSubmitされた時に、GETメソッドで/login ページに飛ぶようにルーティングを設定する必要があるようなので、以下のようにコードを1行追加。

app.get('/', routes.index);
app.get('/users', user.list);
// 以下1行を追加
app.get('/login', user.login);

/loginにアクセスした場合に、routes/ 以下にある user.jsのloginが呼び出されるという形になるため、routes/user.jsを以下のように修正しました

exports.list = function(req, res){
  res.send("respond with a resource");
};
// 以下のコード追加
exports.login = function(req, res){
  res.render("login",{title:"login test"});
};

上記loginの中のres.renderのところで、views/配下にある login.jadeが呼び出されて HTML/CSSが生成されるため、login.jadeを以下のようにひとまず作成しました

block content
  h1= title
  p This is a login test page #{title}

これでひとまずトップページにあるログインフォームから、ログイン先のページに遷移出来るようになります

ただこれだと肝心のログインID&パスワードの値を引き継いでくれません。

そのため、以下のように修正をしていきます。

app.jsの修正

app.use(express.bodyParser()); 
app.use(express.cookieParser());

app.use(express.session({
  secret: "expressSample"
}));

user.jsを修正

exports.login = function(req, res){

    var username = req.query.username;
    var password = req.query.password;
  console.log("username is " + username);
  res.render("login",{
      title:"login test",
      username:username,
      password:password
  });
};

login.jadeを修正

extends layout

block content
  h1= title
  p This is a login test page #{title}
  ul
  li username: #{username}
  li password:  #{password}

上記3点の修正で、ひとまず、ログインフォームに入力したID&パスワードが画面表示されるまで出来上がりました

まとめ

Webアプリを作り慣れてないこともあり、こういう値の受け渡しについての理解が曖昧だったのですがこうやって1つ1つ順を追って文章にまとめながら、検証したことで以前よりも大分理解が深まった気がします

今回の内容をベースに、次回は ACSと連携させたログイン処理という内容で書いていければと思ってます