このシナリオを実装することができました。
私がやったこと...
サーバー上:
-サインイン用の 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);
}
};
}
]);
}
]);