Skip to content

Commit 90bf637

Browse files
authored
fix: Auth token not updated cause page redirect to login (#609)
1 parent c483986 commit 90bf637

File tree

10 files changed

+68
-96
lines changed

10 files changed

+68
-96
lines changed

server/middleware/auth.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ const authPages = [
1010
];
1111

1212
module.exports = async (ctx, next) => {
13-
const { cookies } = ctx;
13+
const { cookies, url } = ctx;
1414

1515
// filter non-asset types
16-
if (ctx.url.endsWith('.map')) {
16+
if (url.endsWith('.map')) {
1717
return;
1818
}
1919

20-
debug('PAGE: %s', ctx.url);
20+
debug('PAGE: %s', url);
2121

2222
/* eslint prefer-destructuring: off */
2323
const page = (ctx.params.page || '').split('/')[0];
24-
const needAuth = authPages.indexOf(page) > -1;
24+
const needAuth = authPages.includes(page);
2525

26-
if (needAuth && !(cookies.get('user') && cookies.get('access_token'))) {
26+
if (needAuth && !cookies.get('refresh_token')) {
2727
// not login
28-
ctx.redirect(`/login?url=${ctx.params.page}`);
28+
ctx.redirect(`/login?redirect_url=${url}`);
2929
}
3030

3131
await next();

server/routes/api.js

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
const Router = require('koa-router');
2+
const debug = require('debug')('app');
23

34
const agent = require('lib/request').default;
45
const logger = require('../logger');
56
const utils = require('../utils');
67

78
const router = new Router();
8-
const header = {};
9-
109
const authEndpoint = 'oauth2/token';
1110

1211
router.post('/api/*', async ctx => {
@@ -23,70 +22,65 @@ router.post('/api/*', async ctx => {
2322

2423
logger({ method, url, body });
2524

26-
const authToken = utils.getTokenGroupFromCtx(ctx);
27-
const unAuthToken = utils.getTokenGroupFromCtx(ctx, 'un_auth');
28-
2925
const browserUrl = ctx.headers.referer;
26+
// todo
3027
const endUrl = browserUrl
3128
.split('/')
3229
.slice(3)
3330
.join('/');
3431
const usingNoAuthToken = endUrl === '' || endUrl.startsWith('apps') || body.isGlobalQuery;
3532
delete body.isGlobalQuery;
3633

37-
// defalut special token params
38-
const tokenData = {
39-
grant_type: 'client_credentials',
34+
const authParams = {
4035
client_id: clientId,
4136
client_secret: clientSecret,
4237
scope: ''
4338
};
4439

45-
// retrieve special token
46-
if (usingNoAuthToken && !unAuthToken.access_token) {
47-
const res = await agent.send('post', [apiServer, authEndpoint].join('/'), tokenData);
48-
49-
if (!res || !res.access_token) {
50-
ctx.throw(401, 'Retrieve token failed');
51-
}
52-
53-
utils.saveTokenResponseToCookie(ctx, res, 'un_auth');
40+
// get current auth info from cookie
41+
const prefix = usingNoAuthToken ? 'no_auth' : '';
42+
const authInfo = utils.getTokenGroupFromCtx(ctx, prefix);
43+
const {
44+
token_type, access_token, refresh_token, expires_in
45+
} = authInfo;
46+
47+
const payload = usingNoAuthToken
48+
? Object.assign(authParams, {
49+
grant_type: 'client_credentials'
50+
})
51+
: Object.assign(authParams, {
52+
grant_type: 'refresh_token',
53+
refresh_token
54+
});
5455

55-
Object.assign(unAuthToken, res);
56+
if (!usingNoAuthToken && !refresh_token) {
57+
// need login
58+
ctx.throw(401, 'refresh token expired');
5659
}
5760

58-
const chooseToken = usingNoAuthToken ? unAuthToken : authToken;
59-
60-
// check if token expired, retrieve refresh token or special token
61-
const { access_token, refresh_token } = chooseToken;
62-
if (!access_token && refresh_token) {
63-
// refresh token params
64-
if (!usingNoAuthToken) {
65-
tokenData.grant_type = 'refresh_token';
66-
tokenData.refresh_token = chooseToken.refresh_token;
67-
}
68-
69-
const res = await agent.send('post', [apiServer, authEndpoint].join('/'), tokenData);
61+
if (!access_token || expires_in < Date.now()) {
62+
const res = await agent.post([apiServer, authEndpoint].join('/'), payload);
63+
debug(`Using refresh token to exchange auth info: %O`, res);
7064

7165
if (!res || !res.access_token) {
72-
ctx.throw(401, 'Refresh token failed');
66+
ctx.throw(401, 'Retrieve access token failed');
7367
}
7468

75-
utils.saveTokenResponseToCookie(ctx, res, usingNoAuthToken ? 'un_auth' : '');
76-
Object.assign(chooseToken, res);
69+
utils.saveTokenResponseToCookie(ctx, res, prefix);
70+
Object.assign(authInfo, res);
7771
}
7872

79-
if (!chooseToken.access_token) {
73+
if (!authInfo.access_token) {
8074
ctx.throw(401, 'Unauthorized: invalid access token');
81-
} else {
82-
header.Authorization = `${chooseToken.token_type} ${chooseToken.access_token}`;
75+
}
8376

84-
delete body.method;
77+
delete body.method;
8578

86-
ctx.body = await agent.send(method, url, body, {
87-
header
88-
});
89-
}
79+
ctx.body = await agent.send(method, url, body, {
80+
header: {
81+
Authorization: `${authInfo.token_type} ${authInfo.access_token}`
82+
}
83+
});
9084
});
9185

9286
module.exports = router;

server/routes/login.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ router.get('/logout', ctx => {
1515
'role',
1616
'expires_in',
1717

18-
'un_auth_access_token',
19-
'un_auth_expires_in',
20-
'un_auth_token_type'
18+
'no_auth_access_token',
19+
'no_auth_expires_in',
20+
'no_auth_token_type'
2121
];
2222
names.forEach(name => ctx.cookies.set(name, '', cookieOptions));
2323
ctx.redirect('/login');

server/utils.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ const oauthResFields = [
1010
];
1111

1212
const getTokenGroupFromCtx = (ctx, group = '') => oauthResFields.reduce((obj, prop) => {
13-
if (group) {
14-
prop = [group, prop].join('_');
15-
}
16-
17-
obj[prop] = ctx.cookies.get(prop);
13+
const key = group ? [group, prop].join('_') : prop;
14+
obj[prop] = ctx.cookies.get(key);
1815
return obj;
1916
}, {});
2017

@@ -30,9 +27,9 @@ const saveTokenResponseToCookie = (
3027

3128
without(oauthResFields, 'id_token').forEach(prop => {
3229
const val = prop === 'expires_in' ? Date.now() + msExpireIn : token_res[prop];
33-
// refresh_token cookie expires after 2 days
30+
// refresh_token cookie expires after 2 weeks
3431
if (prop === 'refresh_token') {
35-
cookieOption.maxAge = 2 * 24 * 60 * 60 * 1000;
32+
cookieOption.maxAge = 2 * 7 * 24 * 60 * 60 * 1000;
3633
} else {
3734
cookieOption.maxAge = msExpireIn;
3835
}

src/App.jsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ class App extends React.Component {
3636
// todo
3737
const hasHeader = user.isNormal || !user.accessToken || user.role === 'user';
3838

39-
if (route.needAuth && !user.accessToken) {
40-
return <Redirect to={`/login?url=${match.url}`} />;
41-
}
42-
4339
if (route.noMatch) {
4440
return <Redirect to="/" />;
4541
}

src/pages/Login/index.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,21 @@ import styles from './index.scss';
1313

1414
@translate()
1515
@inject(({ rootStore }) => ({
16+
rootStore,
1617
store: rootStore.userStore,
1718
user: rootStore.user
1819
}))
1920
@observer
2021
export default class Login extends Component {
22+
constructor(props) {
23+
super(props);
24+
25+
// eslint-disable-next-line
26+
if (props.rootStore.user.isLoggedIn()) {
27+
props.history.replace('/');
28+
}
29+
}
30+
2131
handleSubmit = async params => {
2232
const { store, user, history } = this.props;
2333
const res = await store.oauth2Check(params);
@@ -27,7 +37,7 @@ export default class Login extends Component {
2737
}
2838
const defaultUrl = user.isDev ? '/dashboard/my/apps' : '/dashboard/apps';
2939
if (!(res && res.err)) {
30-
history.push(getUrlParam('url') || defaultUrl);
40+
history.push(getUrlParam('redirect_url') || defaultUrl);
3141
}
3242
};
3343

src/providers/user.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default class UserProvider {
2929
}
3030

3131
isLoggedIn() {
32-
return Boolean(this.accessToken) && this.username;
32+
return this.accessToken && this.username;
3333
}
3434

3535
update(props = {}) {

src/routes/renderRoute.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,13 @@ import { withRouter } from 'react-router';
55
import Header from 'components/Header';
66
import Footer from 'components/Footer';
77
import RouteWrapper from './wrapper';
8-
import { getCookie, setCookie } from '../utils';
8+
import { getCookie } from '../utils';
99

1010
const renderRoute = (match, route, store) => {
11-
if (route.path === 'login') {
12-
const names = [
13-
'access_token',
14-
'token_type',
15-
'access_token_home',
16-
'refresh_token',
17-
'user',
18-
'role'
19-
];
20-
names.forEach(name => setCookie(name, '', -1));
21-
}
22-
2311
const user = store.user || {};
2412
const role = getCookie('role');
2513
const hasHeader = user.isNormal || !user.username || role === 'user';
2614

27-
if (route.needAuth && !user.username) {
28-
return <Redirect to={`/login?url=${match.url}`} />;
29-
}
30-
3115
if (route.noMatch) {
3216
return <Redirect to="/" />;
3317
}

src/stores/Store.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { set } from 'mobx';
22
import agent from 'lib/request';
33
import _ from 'lodash';
4-
import qs from 'query-string';
54

65
export default class Store {
76
constructor(initialState, branch) {
@@ -33,14 +32,6 @@ Store.prototype = {
3332
this.notify(message, 'success');
3433
},
3534
error(message) {
36-
// Can't get token will skip to the login page
37-
if (message === 'Unauthorized') {
38-
const { pathname } = location;
39-
if (pathname && pathname !== '/') {
40-
location.href = `/login?url=${pathname}`;
41-
}
42-
}
43-
4435
this.notify(message, 'error');
4536
},
4637
getValueFromEvent(val) {
@@ -87,10 +78,6 @@ Store.prototype = {
8778
// forward to node backend
8879
const res = await target.post(url, { method, ...params });
8980

90-
if (res && res.status >= 300 && res.status < 400) {
91-
location.href = res.message || '/login';
92-
}
93-
9481
// error handling
9582
if (_.isObject(res) && _.has(res, 'err') && res.status >= 400) {
9683
this.error(res.errDetail || res.err || 'internal error');

src/utils/index.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ export function setCookie(name, value, time) {
3838
}
3939

4040
export function getCookie(name) {
41-
const re = new RegExp(`${name}=([^;]+)`);
42-
const value = re.exec(document.cookie);
43-
return value !== null ? decodeURIComponent(value[1]) : null;
41+
const cookieMap = _.fromPairs(
42+
document.cookie.split(';').map(item => item.trim().split('='))
43+
);
44+
if (cookieMap[name]) {
45+
return decodeURIComponent(cookieMap[name]);
46+
}
47+
return null;
4448
}
4549

4650
export function getPastTime(time) {

0 commit comments

Comments
 (0)