LoginSignup
12
9

More than 3 years have passed since last update.

Nginxとnodejsで認証プロキシを実現する※basic認証じゃないよ!!

Last updated at Posted at 2019-09-27

こんにちは現在サイバーエージェントのサイバーパルという会社でエンジニアをしている@hidexirです。

背景

管理画面の認証を実装するのが少々面倒だったのでロードバランサーで認証を実現しようと思いました。
一般的にベーシック認証やダイナミック認証がnginxを使う場合に思いつきますがさすがにこの認証だ少々怖かったのでアプリケーションで行う方向にしました。あとけっこうまとまっている知見がぱっとみなかったのでまとめました。

作成したのですが今回はそれのまとめです。

読んでほしい人

  • 一通り認証自体は実装経験がある。
  • 管理画面などの認証を一元にしたい。
  • nginxの auth_requestつかってみたい。

管理画面やイントラネットとして活用しているサイトをインターネットに公開する際に認証をアプリケーションに実装するひとが意外に多いです。例えば複数のサブドメインをきって aaa.admin.com bbb.admin.com で動いている管理画面のアプリケーションがあったとするといちいちアプリ内で認証システムを実装するのはコストが少々高いと思います。
管理するは管理コストが高いですよね。その場合はロードバランサー(今回はnginx)を前段に置き認証をアプリケーションの手前で行うことで。これらの問題を解決します。

システムの概要

Untitled Diagram.jpg

説明

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;

まとめ

最初にトークンがなくて500でリダイレクトしている304
スクリーンショット 2019-09-28 2.00.15.png

実際にtokenが帰ってきてるところです。自分はyes_tokenの代わりにランダムに変更してます。

スクリーンショット 2019-09-28 1.55.46.png

本命にgraphqlの管理画面をみれる
スクリーンショット 2019-09-28 1.56.06.png

かなり簡単に認証プロキシシステムを作ることができます。

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9