8

angular、nodejs、およびexpress-jwtを使用して、json Webトークンでスライド有効期限の概念を実装したいと考えています。これを行う方法について少し混乱しており、これらのテクノロジー/フレームワークを使用したセッションに関連するリフレッシュ トークンやその他の資料の例を見つけるのに苦労しています。

私が考えていたいくつかのオプションは

  • 最初のログイン後にリクエストごとに新しいトークンを生成する
  • 発行されたトークンをサーバー側で追跡する

でも正直よくわからないので助けてください

4

1 に答える 1

14

このシナリオを実装することができました。

私がやったこと...

サーバー上:

-サインイン用の API エンドポイントを有効にします。このエンドポイントは、ヘッダーの Json Web トークンで応答します。クライアント側は ($http インターセプターを使用して) それをキャッチし、保存する必要があります (私はローカル ストレージを使用します)。クライアントは、サーバーから送信された更新されたトークンも管理します。

-サーバーへのすべてのリクエストで、トークンを検証するためにミドルウェアをエクスプレスで構成します。最初はexpress-jwtモジュールを試しましたが、jsonwebtokenが私にとっては正しいものでした。

特定のルートでは、ミドルウェアを無効にすることができます。この場合、サインインとサインアウトです。

var jwtCheck = auth.verifyJWT;
jwtCheck.unless = unless;
app.use('/api', jwtCheck.unless({path: [
    '/api/auth/signin',
    '/api/auth/signout'
]}));

- ミドルウェアの verifyJWT は、常にヘッダー内のトークンで応答します。トークンをリフレッシュする必要がある場合は、リフレッシュされた関数が呼び出されます。

jwtLib は、jwt トークンを作成、更新、取得するためのコードが存在する私自身のライブラリです。

function(req, res, next) {
    var newToken,
        token = jwtLib.fetch(req.headers);

    if(token) {
        jwt.verify(token, config.jwt.secret, {
            secret: config.jwt.secret
        }, function(err, decoded) {
            if(err) {
                return res.status(401).send({
                    message: 'User token is not valid'
                });
            }
            //Refresh: If the token needs to be refreshed gets the new refreshed token
            newToken = jwtLib.refreshToken(decoded);
            if(newToken) {
                // Set the JWT refreshed token in http header
                res.set('Authorization', 'Bearer ' + newToken);
                next();
            } else {
                res.set('Authorization', 'Bearer ' + token);
                next();
            }
        });
    } else {
        return res.status(401).send({
            message: 'User token is not present'
        });
    }
};

- リフレッシュ機能 (jwtLib)。引数にはデコードされたトークンが必要であるため、上記の jsonwebtoken が jwt.verify() の呼び出し時にデコードされたトークンを解決することを参照してください。

サインイン中に有効期限が 4 時間のトークンを作成し、更新の有効期限が 1 時間 (1 * 60 * 60 = 3600 秒) の場合、ユーザーが 3 時間以上非アクティブであった場合にトークンが更新されることを意味します。この場合、検証プロセスが失敗するため (1 時間の更新ウィンドウ)、4 時間を超えてはなりません。これにより、トークンがこの時間枠内に期限切れになる場合にのみ、リクエストごとに新しいトークンが生成されるのを回避できます。

module.exports.refreshToken = function(decoded) {
    var token_exp,
        now,
        newToken;

    token_exp = decoded.exp;
    now = moment().unix().valueOf();

    if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) {
        newToken = this.createToken(decoded.user);
        if(newToken) {
            return newToken;
        }
    } else {
       return null;
    }
};

クライアント (Angularjs) で:

-ログイン用のクライアント側を有効にします。これにより、サーバー エンドポイントが呼び出されます。base64 でエンコードされた Http 基本認証を使用します。base64 angular モジュールを使用して email:password をエンコードできます。成功した場合は、トークンを localStorage または Cookie に保存しないことに注意してください。これは、http Interceptor によって管理されます。

//Base64 encode Basic Authorization (email:password)
$http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password);
return $http.post('/api/auth/signin', {skipAuthorization: true});

-リクエストごとにサーバーにトークンを送信し、レスポンスでトークンを保存するように http インターセプターを構成します。更新されたトークンを受信した場合、これを保存する必要があります。

// Config HTTP Interceptors
angular.module('auth').config(['$httpProvider',
    function($httpProvider) {
        // Set the httpProvider interceptor
        $httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector',
            function($q, $location, localStorageService, jwtHelper, $injector) {
                return {
                    request: function(config) {
                        var token = localStorageService.get('authToken');
                        config.headers = config.headers || {};

                        if (token && !jwtHelper.isTokenExpired(token)) {
                            config.headers.Authorization = 'Bearer ' + token;
                        }
                        return config;
                    },
                    requestError: function(rejection) {
                        return $q.reject(rejection);
                    },
                    response: function(response) {
                        //JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage
                        var Authentication = $injector.get('Authentication'),
                            storagedToken = localStorageService.get('authToken'),
                            receivedToken = response.headers('Authorization');
                        if(receivedToken) {
                            receivedToken = Authentication.fetchJwt(receivedToken);
                        }
                        if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) {

                            //Save Auth token to local storage
                            localStorageService.set('authToken', receivedToken);
                        }
                        return response;
                    },
                    responseError: function(rejection) {
                        var Authentication = $injector.get('Authentication');
                        switch (rejection.status) {
                            case 401:
                                // Deauthenticate the global user
                                Authentication.signout();
                                break;
                            case 403:
                                // Add unauthorized behaviour
                                break;
                        }

                        return $q.reject(rejection);
                    }
                };
            }
        ]);
    }
]);
于 2014-12-17T18:14:29.747 に答える