Compare commits
6 Commits
dev
...
hotfix_ren
Author | SHA1 | Date |
---|---|---|
Vicent Llopis | 0b84d847b3 | |
Vicent Llopis | ac83788f1a | |
Vicent Llopis | bc8849d2b8 | |
Vicent Llopis | 66bc2de058 | |
Vicent Llopis | a9885268c2 | |
Vicent Llopis | 6b61d4cca1 |
|
@ -17,23 +17,22 @@ module.exports = Self => {
|
|||
|
||||
Self.renewToken = async function(ctx) {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const created = ctx.req.accessToken.created;
|
||||
const tokenId = ctx.req.accessToken.id;
|
||||
const token = ctx.req.accessToken;
|
||||
|
||||
const now = new Date();
|
||||
const differenceMilliseconds = now - created;
|
||||
const differenceMilliseconds = now - token.created;
|
||||
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
||||
|
||||
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod']});
|
||||
const fields = ['renewPeriod', 'courtesyTime'];
|
||||
const accessTokenConfig = await models.AccessTokenConfig.findOne({fields});
|
||||
|
||||
if (differenceSeconds <= accessTokenConfig.renewPeriod)
|
||||
throw new UserError(`The renew period has not been exceeded`);
|
||||
if (differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime)
|
||||
throw new UserError(`The renew period has not been exceeded`, 'periodNotExceeded');
|
||||
|
||||
await Self.logout(tokenId);
|
||||
const user = await Self.findById(userId);
|
||||
await Self.logout(token.id);
|
||||
const user = await Self.findById(token.userId);
|
||||
const accessToken = await user.createAccessToken();
|
||||
|
||||
return {token: accessToken.id, created: accessToken.created};
|
||||
return {id: accessToken.id, ttl: accessToken.ttl};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -76,6 +76,6 @@ module.exports = Self => {
|
|||
|
||||
let loginInfo = Object.assign({password}, userInfo);
|
||||
token = await Self.login(loginInfo, 'user');
|
||||
return {token: token.id, created: token.created};
|
||||
return {token: token.id, ttl: token.ttl};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"courtesyTime": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"renewInterval": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
CREATE TABLE `salix`.`accessTokenConfig` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`renewPeriod` int(10) unsigned DEFAULT NULL,
|
||||
`courtesyTime` int(10) unsigned DEFAULT NULL,
|
||||
`renewInterval` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
INSERT IGNORE INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `renewInterval`)
|
||||
INSERT IGNORE INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `courtesyTime`, `renewInterval`)
|
||||
VALUES
|
||||
(1, 21600, 300);
|
||||
(1, 21600, 5, 300);
|
||||
|
|
|
@ -59,12 +59,13 @@ export default class Auth {
|
|||
password: password || undefined
|
||||
};
|
||||
|
||||
const now = new Date();
|
||||
return this.$http.post('VnUsers/signIn', params)
|
||||
.then(json => this.onLoginOk(json, remember));
|
||||
.then(json => this.onLoginOk(json, now, remember));
|
||||
}
|
||||
|
||||
onLoginOk(json, remember) {
|
||||
this.vnToken.set(json.data.token, json.data.created, remember);
|
||||
onLoginOk(json, now, remember) {
|
||||
this.vnToken.set(json.data.token, now, json.data.ttl, remember);
|
||||
|
||||
return this.loadAcls().then(() => {
|
||||
let continueHash = this.$state.params.continue;
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import ngModule from '../module';
|
||||
import HttpError from 'core/lib/http-error';
|
||||
|
||||
interceptor.$inject = ['$q', 'vnApp', 'vnToken', '$translate'];
|
||||
function interceptor($q, vnApp, vnToken, $translate) {
|
||||
interceptor.$inject = ['$q', 'vnApp', '$translate'];
|
||||
function interceptor($q, vnApp, $translate) {
|
||||
let apiPath = 'api/';
|
||||
let token = sessionStorage.getItem('vnToken')
|
||||
?? localStorage.getItem('vnToken');
|
||||
|
||||
return {
|
||||
setToken(newToken) {
|
||||
token = newToken;
|
||||
},
|
||||
setApiPath(path) {
|
||||
apiPath = path;
|
||||
},
|
||||
|
@ -14,8 +19,8 @@ function interceptor($q, vnApp, vnToken, $translate) {
|
|||
|
||||
if (config.url.charAt(0) !== '/' && apiPath)
|
||||
config.url = `${apiPath}${config.url}`;
|
||||
if (vnToken.token)
|
||||
config.headers.Authorization = vnToken.token;
|
||||
if (token)
|
||||
config.headers.Authorization = token;
|
||||
if ($translate.use())
|
||||
config.headers['Accept-Language'] = $translate.use();
|
||||
if (config.filter) {
|
||||
|
|
|
@ -6,37 +6,118 @@ import ngModule from '../module';
|
|||
* @property {String} token The current login token or %null
|
||||
*/
|
||||
export default class Token {
|
||||
constructor() {
|
||||
try {
|
||||
this.token = sessionStorage.getItem('vnToken');
|
||||
this.created = sessionStorage.getItem('vnTokenCreated');
|
||||
if (!this.token) {
|
||||
this.token = localStorage.getItem('vnToken');
|
||||
this.created = localStorage.getItem('vnTokenCreated');
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
set(token, created, remember) {
|
||||
this.unset();
|
||||
try {
|
||||
if (remember) {
|
||||
localStorage.setItem('vnToken', token);
|
||||
localStorage.setItem('vnTokenCreated', created);
|
||||
} else {
|
||||
sessionStorage.setItem('vnToken', token);
|
||||
sessionStorage.setItem('vnTokenCreated', created);
|
||||
}
|
||||
} catch (e) {}
|
||||
constructor(vnInterceptor, $http, $rootScope) {
|
||||
Object.assign(this, {
|
||||
vnInterceptor,
|
||||
$http,
|
||||
$rootScope
|
||||
});
|
||||
|
||||
this.token = token;
|
||||
this.created = created;
|
||||
try {
|
||||
this.getStorage(sessionStorage);
|
||||
this.remember = true;
|
||||
|
||||
if (!this.token) {
|
||||
this.getStorage(localStorage);
|
||||
this.remember = false;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
set(token, created, ttl, remember) {
|
||||
this.unset();
|
||||
|
||||
Object.assign(this, {
|
||||
token,
|
||||
created,
|
||||
ttl,
|
||||
remember
|
||||
});
|
||||
this.vnInterceptor.setToken(token);
|
||||
|
||||
try {
|
||||
if (remember)
|
||||
this.setStorage(localStorage, token, created, ttl);
|
||||
else
|
||||
this.setStorage(sessionStorage, token, created, ttl);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
unset() {
|
||||
localStorage.removeItem('vnToken');
|
||||
sessionStorage.removeItem('vnToken');
|
||||
this.token = null;
|
||||
this.created = null;
|
||||
this.ttl = null;
|
||||
this.remember = null;
|
||||
this.vnInterceptor.setToken(null);
|
||||
|
||||
this.removeStorage(localStorage);
|
||||
this.removeStorage(sessionStorage);
|
||||
}
|
||||
|
||||
getStorage(storage) {
|
||||
this.token = storage.getItem('vnToken');
|
||||
if (!this.token) return;
|
||||
const created = storage.getItem('vnTokenCreated');
|
||||
this.created = created && new Date(created);
|
||||
this.renewPeriod = storage.getItem('vnTokenRenewPeriod');
|
||||
}
|
||||
|
||||
setStorage(storage, token, created, ttl) {
|
||||
storage.setItem('vnToken', token);
|
||||
storage.setItem('vnTokenCreated', created.toJSON());
|
||||
storage.setItem('vnTokenTtl', ttl);
|
||||
}
|
||||
|
||||
removeStorage(storage) {
|
||||
storage.removeItem('vnToken');
|
||||
storage.removeItem('vnTokenCreated');
|
||||
storage.removeItem('vnTokenTtl');
|
||||
}
|
||||
|
||||
fetchConfig() {
|
||||
const filter = {fields: ['renewInterval', 'renewPeriod']};
|
||||
this.$http.get('AccessTokenConfigs/findOne', {filter}).then(res => {
|
||||
const data = res.data;
|
||||
if (!data) return;
|
||||
this.renewPeriod = data.renewPeriod;
|
||||
this.stopRenewer();
|
||||
this.inservalId = setInterval(() => this.checkValidity(), data.renewInterval * 1000);
|
||||
this.checkValidity();
|
||||
});
|
||||
}
|
||||
|
||||
checkValidity() {
|
||||
if (this.checking || !this.created) return;
|
||||
this.checking = true;
|
||||
const renewPeriod = Math.min(this.ttl, this.renewPeriod) * 1000;
|
||||
const maxDate = this.created.getTime() + renewPeriod;
|
||||
const now = new Date();
|
||||
|
||||
if (now.getTime() <= maxDate) {
|
||||
this.checking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$http.post('VnUsers/renewToken')
|
||||
.then(res => {
|
||||
const token = res.data;
|
||||
this.set(token.id, now, token.ttl, this.remember);
|
||||
})
|
||||
.catch(res => {
|
||||
if (res.data?.error?.code !== 'periodNotExceeded')
|
||||
throw res;
|
||||
})
|
||||
.finally(() => {
|
||||
this.checking = false;
|
||||
});
|
||||
}
|
||||
|
||||
stopRenewer() {
|
||||
clearInterval(this.inservalId);
|
||||
}
|
||||
}
|
||||
Token.$inject = ['vnInterceptor', '$http', '$rootScope'];
|
||||
|
||||
ngModule.service('vnToken', Token);
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<button class="buttonAccount">
|
||||
<img
|
||||
id="user"
|
||||
ng-src="{{$ctrl.getImageUrl()}}"
|
||||
ng-src="{{::$ctrl.getImageUrl()}}"
|
||||
ng-click="userPopover.show($event)"
|
||||
translate-attr="{title: 'Account'}"
|
||||
on-error-src/>
|
||||
|
|
|
@ -3,14 +3,13 @@ import Component from 'core/lib/component';
|
|||
import './style.scss';
|
||||
|
||||
export class Layout extends Component {
|
||||
constructor($element, $, vnModules, vnToken) {
|
||||
constructor($element, $, vnModules) {
|
||||
super($element, $);
|
||||
this.modules = vnModules.get();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.getUserData();
|
||||
this.getAccessTokenConfig();
|
||||
}
|
||||
|
||||
getUserData() {
|
||||
|
@ -32,41 +31,11 @@ export class Layout extends Component {
|
|||
window.location.reload();
|
||||
}
|
||||
|
||||
getAccessTokenConfig() {
|
||||
this.$http.get('AccessTokenConfigs').then(json => {
|
||||
const firtsResult = json.data[0];
|
||||
if (!firtsResult) return;
|
||||
this.renewPeriod = firtsResult.renewPeriod;
|
||||
this.renewInterval = firtsResult.renewInterval;
|
||||
|
||||
const intervalMilliseconds = firtsResult.renewInterval * 1000;
|
||||
this.inservalId = setInterval(this.checkTokenValidity.bind(this), intervalMilliseconds);
|
||||
});
|
||||
}
|
||||
|
||||
checkTokenValidity() {
|
||||
const now = new Date();
|
||||
const differenceMilliseconds = now - new Date(this.vnToken.created);
|
||||
const differenceSeconds = Math.floor(differenceMilliseconds / 1000);
|
||||
|
||||
if (differenceSeconds > this.renewPeriod) {
|
||||
this.$http.post('VnUsers/renewToken')
|
||||
.then(json => {
|
||||
if (json.data.token) {
|
||||
let remember = true;
|
||||
if (window.sessionStorage.vnToken) remember = false;
|
||||
|
||||
this.vnToken.set(json.data.token, json.data.created, remember);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
clearInterval(this.inservalId);
|
||||
this.vnToken.stopRenewer();
|
||||
}
|
||||
}
|
||||
Layout.$inject = ['$element', '$scope', 'vnModules', 'vnToken'];
|
||||
Layout.$inject = ['$element', '$scope', 'vnModules'];
|
||||
|
||||
ngModule.vnComponent('vnLayout', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -37,49 +37,4 @@ describe('Component vnLayout', () => {
|
|||
expect(url).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAccessTokenConfig()', () => {
|
||||
it(`should set the renewPeriod and renewInterval properties in localStorage`, () => {
|
||||
const response = [{
|
||||
renewPeriod: 100,
|
||||
renewInterval: 5
|
||||
}];
|
||||
|
||||
$httpBackend.expect('GET', `AccessTokenConfigs`).respond(response);
|
||||
controller.getAccessTokenConfig();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.renewPeriod).toBe(100);
|
||||
expect(controller.renewInterval).toBe(5);
|
||||
expect(controller.inservalId).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkTokenValidity()', () => {
|
||||
it(`should not call renewToken and not set vnToken in the controller`, () => {
|
||||
controller.renewPeriod = 100;
|
||||
controller.vnToken.created = new Date();
|
||||
|
||||
controller.checkTokenValidity();
|
||||
|
||||
expect(controller.vnToken.token).toBeNull();
|
||||
});
|
||||
|
||||
it(`should call renewToken and set vnToken properties in the controller`, () => {
|
||||
const response = {
|
||||
token: 999,
|
||||
created: new Date()
|
||||
};
|
||||
controller.renewPeriod = 100;
|
||||
const oneHourBefore = new Date(Date.now() - (60 * 60 * 1000));
|
||||
controller.vnToken.created = oneHourBefore;
|
||||
|
||||
$httpBackend.expect('POST', `VnUsers/renewToken`).respond(response);
|
||||
controller.checkTokenValidity();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.vnToken.token).toBe(999);
|
||||
expect(controller.vnToken.created).toEqual(response.created);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,7 +11,8 @@ function config($stateProvider, $urlRouterProvider) {
|
|||
abstract: true,
|
||||
template: '<vn-layout></vn-layout>',
|
||||
resolve: {
|
||||
config: ['vnConfig', vnConfig => vnConfig.initialize()]
|
||||
config: ['vnConfig', vnConfig => vnConfig.initialize()],
|
||||
token: ['vnToken', vnToken => vnToken.fetchConfig()]
|
||||
}
|
||||
})
|
||||
.state('outLayout', {
|
||||
|
|
Loading…
Reference in New Issue