40
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swagger定義ファイルにSecurityDefinitionsを定義する

Last updated at Posted at 2018-08-26

前回、SwaggerでRESTful環境をスマートに構築しました。

SwaggerでRESTful環境を構築する

使いこなしていく上で、手間取ったことの一つに、SecurityDefinitionsの定義があります。
SwaggerにおけるSecurityDefinitionsとは、HTTPヘッダのAuthorizationを使って、ユーザ・パスワードによるベーシック認証やOpenID Connectのトークン認証するための定義です。

swagger-nodeを使ったRESTful環境でもちゃんと対応しているんです!
せっかくなので、使ってみます。

Swagger SecurityDefitions定義

Swagger 2.0では、以下の3つの方式が定義可能です。

  • Basic認証
  • API Key
  • OAuth2 認証フロー

[参考情報]
https://swagger.io/docs/specification/2-0/authentication/basic-authentication/

このうち、OAuth2 認証フローは、細かな設定ができるようなのですが、設定が面倒だったり、Swagger 3.0でまた仕様がかわるので、使うのをやめて、API Keyで代用します。トークンはどうなっちゃうの?と心配されるかもしれませんが、以降で、それっぽくトークン検証していますので、お楽しみに。

それでは早速、定義方法を示します。

共通の定義をしてから、各APIにどの定義を使うかという順番です。

まず定義から。

swagger.yaml
securityDefinitions:
  basicAuth:
    type: basic
  tokenAuth:
    type: "apiKey"
    name: "Authorization"
    in: "header"

見ての通りですね。
名前は何でもよいのですが、それぞれ「basicAuth」と「tokenAuth」という定義の名前を付けてみました。

それらを実際に使うAPIの定義では、以下のように指定します。security: のところです。
これだけです。

swagger.yaml
paths:
  /test_auth:
    post:
      x-swagger-router-controller: test
      operationId: test_post
      security:
        - basicAuth: []  もしくは – tokenAuth: []
      tags:
      - test
      description: Post message to test
      parameters:
        - in: body
          name: body
          required: true
          schema:
            $ref: '#/definitions/SimpleRequest'
      responses:
        '200':
          description: Success
          schema:
            $ref: '#/definitions/SimpleResponse'
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"

それではさっそくSwagger-EditorでSwagger定義ファイルを見てみましょう。
ページの先頭あたりに、Authorize というボタンが増えています。

image.png

押してみると、

image.png

上記のように、ベーシック認証では、ユーザ名とパスワードが入れられるようになりました。
トークン認証においても、Authorizationヘッダに値を指定できるようになりました。
これらは、Swagger定義ファイルのSecurityDefinitionsの定義部分に該当します。

次は、API定義の右端の所に、錠のマークがついているのがわかりますでしょうか?

image.png

「Try it out」で実行してみると、basicAuthなのかtokenAuthなのかに従って、Authorizationヘッダに値を勝手につけてくれます。
しかも、ベーシック認証の場合には、ユーザ名・パスワードが以下のようにエンコードしてくれますので、至れり尽くせりです。

Authorization: Basic base64Encode("ユーザ名:パスワード”)

ここまでやってくれるSwagger-Editorは素晴らしいとしか言いようがないですね。

Swagger実行環境の整備

実は、上記のSwagger定義ファイルにSecurityDefinitionsを定義した状態でSwagger実行環境を立ち上げると、実行に失敗してしまいます。定義が足りないという理由です。

そこで、以下の定義を追加することで、Swaggerを実行できる状態になります。
config.swaggerSecurityHandlersの部分です。

app.js

・・・・

var config = {
  appRoot: __dirname // required config
};

config.swaggerSecurityHandlers = {
  basicAuth : function (req, authOrSecDef, scopesOrApiKey, cb) {
    // todo
    // cb() for success
    // cb(error) for error
  },
  tokenAuth : function (req, authOrSecDef, scopesOrApiKey, cb) {
    // todo
    // cb() for success
    // cb(error) for error
  }
};

SwaggerExpress.create(config, function(err, swaggerExpress) {

・・・

basicAuthとtokenAuthという名称は、SecurityDefinitionsで定義したあの名前です。
これでエラーにはならなくなるのですが、ついでに便利なロジックを埋め込んどいてあげましょう。
Authorizationヘッダに入力された内容を解析して、コントローラに渡してあげる、というものです。そうすることで、コントローラ側で、ユーザ名とパスワードが合っているか、など判断することができるようになります。

最終的にはこの通りです。

app.js

var jwt_decode = require('jwt-decode');

config.swaggerSecurityHandlers = {
  basicAuth : function (req, authOrSecDef, scopesOrApiKey, cb) {
    try{
      var basic = req.headers.authorization.trim();
      if(basic.toLowerCase().startsWith('basic '))
        basic = basic.slice(6).trim();

      var buf = new Buffer(basic, 'base64');
      var ascii = buf.toString('ascii');

      req.requestContext = {
        authorizer : {
          basic : ascii.split(':')
        }
      };

      cb();
    }catch(error){
      cb(error);
    }
  },
  tokenAuth : function (req, authOrSecDef, scopesOrApiKey, cb) {
    try{
      var decoded = jwt_decode(scopesOrApiKey);

      req.requestContext = {
        authorizer : {
          claims : decoded
        }
      };

      cb();
    }catch(error){
      cb(error);
    }
  }
};

まずは、ベーシック認証(basicAuth)から。
AuthorizationヘッダにはBase64エンコードされてきますので、それをデコードします。
デコードした結果を、req.requestContext.authorizer.basicに、ユーザ名とパスワードの配列として、コントローラに渡します。

次は、トークン認証(tokenAuth)。
トークンは、JWTでエンコードされています。それを解析するのに便利なモジュール「jwt-decode」を使わせていただきました。
これを使ってデコードした結果をreq.requestContext.authorizer.claimsに、subやらaudやらissやら、トークンの内容をそのまま設定してコントローラに渡しています。
以下も忘れずに実行しておいてください。

npm install jwt-decode --save

本来であれば、JWTの公開鍵を使って検証するのですが、今回は単純にデコードだけにしました。ですので、上記のコードでは、トークンの生成元が正しいかどうかは確認していないので、そのまま運用には使わないで下さい。正しくは、ここら辺を参考にしてください。

[参考情報]
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html

以上で、Swagger-Editor上から、ユーザパスワードやトークンを指定して、API呼び出しができるようになりました。
swagger-nodeは本当に素晴らしいですね。

ご参考

最終系はこちらです。
SwaggerでLambdaのデバッグ環境を作る(1)

以上

40
39
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
40
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?