undefined

bokuweb.me

node passportをつかって、はてなOAuth認証をやってみた

なんとなくやってみた。

入っていなければexpressのインストール

npm install express-generator -g

express myApp

cd myApp && npm install

cd myApp

必要に応じてcoffeeに変換。(要js2coffee)。

js2coffee app.js > app.coffee

passportとpassport-hatenaのインストール

npm install passport --save

npm install passport-hatena --save

session使用のためexpress-sessionのインストール

npm install express-session --save

package.jsonはこんな感じ

{
  "name": "tana",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.10.2",
    "cookie-parser": "~1.3.3",
    "debug": "~2.1.1",
    "express": "~4.11.1",
    "jade": "~1.9.1",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "passport": "~0.2.1",
    "passport-hatena": "0.0.2",
    "express-session": "~1.10.3"
  }
}

ソース

・app.coffee ほとんどサンプルのまま

express = require('express')
path = require('path')
favicon = require('serve-favicon')
logger = require('morgan')
cookieParser = require('cookie-parser')
bodyParser = require('body-parser')
routes = require('./routes/index')
users = require('./routes/users')
app = express()
passport = require('passport')
util = require('util')
HatenaStrategy = require('passport-hatena').Strategy
session = require('express-session')

HATENA_CONSUMER_KEY = "xxxxx"
HATENA_SECRET_KEY = "xxxxx"


# Passport session setup.
#   To support persistent login sessions, Passport needs to be able to
#   serialize users into and deserialize users out of the session.  Typically,
#   this will be as simple as storing the user ID when serializing, and finding
#   the user by ID when deserializing.  However, since this example does not
#   have a database of user records, the complete Hatena profile is serialized
#   and deserialized.
passport.serializeUser (user, done)->
  done(null, user)

passport.deserializeUser (obj, done)->
  done(null, obj)


# Use the HatenaStrategy within Passport.
#   Strategies in passport require a `verify` function, which accept
#   credentials (in this case, a token, tokenSecret, and Hatena profile), and
#   invoke a callback with a user object.
passport.use(new HatenaStrategy(
    consumerKey: HATENA_CONSUMER_KEY
    consumerSecret: HATENA_SECRET_KEY
    callbackURL: "http://127.0.0.1:3000/auth/hatena/callback"
  (token, tokenSecret, profile, done)->
    # asynchronous verification, for effect...
    process.nextTick ()->

      # To keep the example simple, the user's Hatena profile is returned to
      # represent the logged-in user.  In a typical application, you would want
      # to associate the Hatena account with a user record in your database,
      # and return that user instead.
      return done(null, profile)
  )
)

# view engine setup
app.set 'views', path.join(__dirname, 'views')
app.set 'view engine', 'jade'

# uncomment after placing your favicon in /public
#app.use(favicon(__dirname + '/public/favicon.ico'));
app.use logger('dev')
app.use bodyParser.json()
app.use bodyParser.urlencoded(extended: false)
app.use cookieParser()
app.use express.static(path.join(__dirname, 'public'))
app.use session
  secret: 'keyboard cat'

# Initialize Passport!  Also use passport.session() middleware, to support
# persistent login sessions (recommended).
app.use passport.initialize()
app.use passport.session()

#app.use '/', routes
app.use '/users', users


app.get '/', (req, res)->
  res.render 'index', { user: req.user }


#app.get '/account', ensureAuthenticated, (req, res)->
#  res.render 'account', { user: req.user }

app.get '/login', (req, res)->
  res.render 'login', { user: req.user }

# GET /auth/hatena
#   Use passport.authenticate() as route middleware to authenticate the
#   request.  The first step in Hatena authentication will involve redirecting
#   the user to hatena.ne.jp.  After authorization, Hatena will redirect the user
#   back to this application at /auth/hatena/callback
app.get '/auth/hatena',
  passport.authenticate 'hatena', { scope: ['read_public'] }

# GET /auth/hatena/callback
#   Use passport.authenticate() as route middleware to authenticate the
#   request.  If authentication fails, the user will be redirected back to the
#   login page.  Otherwise, the primary route function function will be called,
#   which, in this example, will redirect the user to the home page.
app.get '/auth/hatena/callback',
  passport.authenticate 'hatena', { failureRedirect: '/login' }
  (req, res)->
    res.redirect('/')

#app.get '/logout', (req, res)->
#  req.logout()
#  res.redirect('/')


# error handlers
# development error handler
# will print stacktrace
if app.get('env') == 'development'
  app.use (err, req, res, next) ->
    res.status err.status or 500
    res.render 'error',
      message: err.message
      error: err
    return

# catch 404 and forward to error handler
app.use (req, res, next) ->
  err = new Error('Not Found')
  err.status = 404
  next err
  return

# Simple route middleware to ensure user is authenticated.
#   Use this route middleware on any resource that needs to be protected.  If
#   the request is authenticated (typically via a persistent login session),
#   the request will proceed.  Otherwise, the user will be redirected to the
#   login page.
ensureAuthenticated = (req, res, next)->
  if req.isAuthenticated() then return next()
  res.redirect('/login')

module.exports = app

・index.jade

extends layout

block content
  if !user
    h2 Welcome! Please log in.
    a(href="/auth/hatena") Login with Hatena
  else
    h2 Hello,#{user.displayName}
    a(href="/logout") Logout

はてな側の設定

f:id:bokuweb:20150312204859p:plain

コンシューマキーとトークンシークレットが表示されているためソースに記述。

こんな感じ

開始 npm start

127.0.0.1:3000にアクセス f:id:bokuweb:20150312205008p:plain

f:id:bokuweb:20150312205020p:plain

f:id:bokuweb:20150312205028p:plain

わーい。

リポジトリ

bokuweb/passport-test · GitHub

感想

結構簡単にできた。 使い方が翻訳されていて参考になる。

Passport - Node.jsのための、シンプルで使いどころを選ばない認証モジュール