こんにちは現在サイバーエージェントのサイバーパルという会社でエンジニアをしている@hidexirです。
背景
管理画面の認証を実装するのが少々面倒だったのでロードバランサーで認証を実現しようと思いました。
一般的にベーシック認証やダイナミック認証がnginxを使う場合に思いつきますがさすがにこの認証だ少々怖かったのでアプリケーションで行う方向にしました。あとけっこうまとまっている知見がぱっとみなかったのでまとめました。
作成したのですが今回はそれのまとめです。
読んでほしい人
- 一通り認証自体は実装経験がある。
- 管理画面などの認証を一元にしたい。
- nginxの
auth_request
つかってみたい。
管理画面やイントラネットとして活用しているサイトをインターネットに公開する際に認証をアプリケーションに実装するひとが意外に多いです。例えば複数のサブドメインをきって aaa.admin.com bbb.admin.com で動いている管理画面のアプリケーションがあったとするといちいちアプリ内で認証システムを実装するのはコストが少々高いと思います。
管理するは管理コストが高いですよね。その場合はロードバランサー(今回はnginx)を前段に置き認証をアプリケーションの手前で行うことで。これらの問題を解決します。
システムの概要
説明
nginxがport80
にて起動。 認証にて200OKを返したら本命にリクエストを流す。失敗の場合は認証ページにリダイレクト。
/login
認証アプリケーションport 3000
/auth_request
認証アプリケーションport 3000
/
本命のアプリケーションport 4000
nginx auth_request
server {
listen 80;
server_name sample.jp;
# loginページ
location /login {
proxy_set_header Host $host;
proxy_pass_request_body on;
proxy_no_cache "1";
proxy_pass http://localhost:3000;
}
# auth のtoken確認
location /auth_request {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_pass_request_body on;
proxy_no_cache "1";
}
# ログイン後のメインアプリ
location / {
auth_request /auth_request; # auth_requestにて上のプロキシさせ200OKを確認してくれる
error_page 500 = /login; #login失敗の場合リダイレクト
proxy_set_header Host $http_host;
proxy_pass http://localhost:4000;
}
}
nodejsによる簡易的な認証アプリの説明。
loginの部分→最後にトークンをCookieにセット
extends layout
block content
h1= title
p #{content}
form(method="post" action="/login")
input(type="text" name="userName")
input(type="text" name="password")
input(type="submit" name="送信")
※実際にはもっと強い暗号やDB問い合わせやJWTなでトークンの安全性は担保してください。
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('login', { title: 'Express' });
});
router.post('/', function(req, res, next) {
if(req.body.userName=="ice" || req.body.password=="man") {
res.cookie('token', 'yes_token', {maxAge:60000000, httpOnly:false});//ユーザーネームが"ice" パスワードが"man"の場合はいまはcookieに token : yes_token を返却している。
res.send("sucsess!");
}
res.send("error!");
});
module.exports = router;
トークンの有用性の確認
※実際にはもっと強い暗号やDB問い合わせやJWTなでトークンの安全性は担保してください。
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
if(req.cookies.token == "yes_token"){
return res.send('sucsess!!') //成功したばあいは200OK
}
res.status(500).send('auth failed')//失敗の場合は500 errorとしている
});
module.exports = router;
まとめ
実際にtokenが帰ってきてるところです。自分はyes_tokenの代わりにランダムに変更してます。
かなり簡単に認証プロキシシステムを作ることができます。