Skip to content

Commit e8baaeb

Browse files
committed
adding Session Management
1 parent c5d1fe9 commit e8baaeb

6 files changed

Lines changed: 126 additions & 42 deletions

File tree

projectforge-webapp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"node-sass": "^4.11.0",
1313
"prop-types": "^15.7.2",
1414
"react": "^16.8.3",
15+
"react-cookies": "^0.1.0",
1516
"react-dom": "^16.8.3",
1617
"react-redux": "^6.0.1",
1718
"react-scripts": "2.1.5",
Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,95 @@
1-
import { getServiceURL } from '../utilities/rest';
1+
import cookies from 'react-cookies';
2+
3+
import {
4+
getAuthenticationHeaders,
5+
getLoginHeaders,
6+
getServiceURL,
7+
handleHTTPErrors,
8+
} from '../utilities/rest';
29

310
export const USER_LOGIN_BEGIN = 'USER_LOGIN_BEGIN';
411
export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS';
512
export const USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE';
13+
614
export const USER_LOGOUT = 'USER_LOGOUT';
715

8-
export const userLoginBegin = keepSignedIn => ({
16+
const userLoginBegin = keepSignedIn => ({
917
type: USER_LOGIN_BEGIN,
1018
payload: {
1119
keepSignedIn,
1220
},
1321
});
1422

15-
export const userLoginSuccess = (userId, authenticationToken) => ({
23+
const userLoginSuccess = (userId, authenticationToken) => ({
1624
type: USER_LOGIN_SUCCESS,
1725
payload: {
1826
userId,
1927
authenticationToken,
2028
},
2129
});
2230

23-
export const userLoginFailure = error => ({
31+
const userLoginFailure = error => ({
2432
type: USER_LOGIN_FAILURE,
2533
payload: {
2634
error,
2735
},
2836
});
2937

30-
export const userLogout = () => ({
38+
const userLogout = () => ({
3139
type: USER_LOGOUT,
3240
});
3341

34-
const authenticationUsername = 'Authentication-Username';
35-
const authenticationPassword = 'Authentication-Password';
42+
const USER_ID_COOKIE = 'USER_ID';
43+
const TOKEN_COOKIE = 'TOKEN';
3644

3745
export const login = (username, password, keepSignedIn) => (dispatch) => {
3846
dispatch(userLoginBegin(keepSignedIn));
3947
return fetch(
4048
getServiceURL('authenticate/getToken'),
41-
// 'https://httpbin.org/get',
4249
{
4350
method: 'GET',
44-
headers: {
45-
[authenticationUsername]: username,
46-
[authenticationPassword]: password,
47-
},
51+
headers: getLoginHeaders(username, password),
4852
},
4953
)
50-
// TODO: HANDLE HTTPS ERRORS?
54+
.then(handleHTTPErrors)
5155
.then(response => response.json())
52-
.then((json) => {
53-
// TODO: SAVE ID AND TOKEN AS COOKIES WHEN KEEPSIGNEDIN IS SET
54-
dispatch(userLoginSuccess(json.id, json.token));
56+
.then(({ id, authenticationToken }) => {
57+
if (keepSignedIn) {
58+
cookies.save(USER_ID_COOKIE, id);
59+
cookies.save(TOKEN_COOKIE, authenticationToken);
60+
}
61+
62+
dispatch(userLoginSuccess(id, authenticationToken));
5563
})
5664
.catch(error => dispatch(userLoginFailure(error)));
5765
};
66+
67+
export const logout = () => (dispatch) => {
68+
cookies.remove(USER_ID_COOKIE);
69+
cookies.remove(TOKEN_COOKIE);
70+
71+
dispatch(userLogout());
72+
};
73+
74+
export const loadSessionIfAvailable = () => (dispatch) => {
75+
const userID = cookies.load(USER_ID_COOKIE);
76+
const token = cookies.load(TOKEN_COOKIE);
77+
78+
if (!userID || !token) {
79+
return;
80+
}
81+
82+
dispatch(userLoginBegin(true));
83+
84+
fetch(
85+
getServiceURL('authenticate/initialContact'),
86+
{
87+
method: 'GET',
88+
headers: getAuthenticationHeaders(userID, token),
89+
},
90+
)
91+
.then(handleHTTPErrors)
92+
.then(response => response.json)
93+
.then(() => dispatch(userLoginSuccess(userID, token)))
94+
.catch(error => dispatch(userLoginFailure(error)));
95+
};
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
export {
2-
login as loginUser, userLoginBegin,
2+
USER_LOGIN_BEGIN,
3+
USER_LOGIN_SUCCESS,
4+
USER_LOGIN_FAILURE,
5+
USER_LOGOUT,
6+
login as loginUser,
7+
logout as logoutUser,
8+
loadSessionIfAvailable,
39
} from './authentication';
Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,49 @@
1-
import React from 'react';
1+
import React, { Component } from 'react';
22
import { connect } from 'react-redux';
33
import PropTypes from 'prop-types';
44
import TopBar from '../components/base/topbar';
55
import Footer from '../components/base/footer';
66
import LoginView from '../components/authentication/LoginView';
7-
import { loginUser } from '../actions';
8-
9-
function ProjectForge({ loggedIn, loginUser: login }) {
10-
let content;
11-
12-
if (loggedIn) {
13-
content = 'Logged In';
14-
} else {
15-
content = (
16-
<LoginView
17-
// TODO: EXAMPLE DATA, REPLACE WITH REAL DATA FROM REST API
18-
motd="Please try user demo with password demo123. Have a lot of fun!"
19-
login={login}
20-
/>
21-
);
7+
import { loadSessionIfAvailable, loginUser } from '../actions';
8+
9+
class ProjectForge extends Component {
10+
componentDidMount() {
11+
const { loadSessionIfAvailable: loadSession } = this.props;
12+
13+
loadSession();
2214
}
2315

24-
return (
25-
<React.Fragment>
26-
<TopBar />
27-
{content}
28-
<Footer version="Version 6.25-SNAPSHOT, 2019-02-26" updateAvailable />
29-
</React.Fragment>
30-
);
16+
17+
render() {
18+
const { loggedIn, loginUser: login } = this.props;
19+
let content;
20+
21+
if (loggedIn) {
22+
content = 'Logged In';
23+
} else {
24+
content = (
25+
<LoginView
26+
// TODO: EXAMPLE DATA, REPLACE WITH REAL DATA FROM REST API
27+
motd="Please try user demo with password demo123. Have a lot of fun!"
28+
login={login}
29+
/>
30+
);
31+
}
32+
33+
return (
34+
<React.Fragment>
35+
<TopBar />
36+
{content}
37+
<Footer version="Version 6.25-SNAPSHOT, 2019-02-26" updateAvailable />
38+
</React.Fragment>
39+
);
40+
}
3141
}
3242

3343
ProjectForge.propTypes = {
3444
loginUser: PropTypes.func.isRequired,
3545
loggedIn: PropTypes.bool.isRequired,
46+
loadSessionIfAvailable: PropTypes.func.isRequired,
3647
};
3748

3849
const mapStateToProps = state => ({
@@ -41,6 +52,7 @@ const mapStateToProps = state => ({
4152

4253
const actions = {
4354
loginUser,
55+
loadSessionIfAvailable,
4456
};
4557

4658
export default connect(mapStateToProps, actions)(ProjectForge);

projectforge-webapp/src/utilities/rest.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,30 @@ const createQueryParams = params => Object.keys(params)
55
.map(key => `${key}=${encodeURI(params[key])}`)
66
.join('&');
77

8-
/* eslint-disable-next-line import/prefer-default-export */
98
export const getServiceURL = (serviceURL, params) => {
109
if (params) {
1110
return `${baseURL}/${serviceURL}?${createQueryParams(params)}`;
1211
}
1312

1413
return `${baseURL}/${serviceURL}`;
1514
};
15+
16+
// ATTENTION: Only for the Login Process.
17+
export const getLoginHeaders = (username, password) => ({
18+
'Authentication-Username': username,
19+
'Authentication-Password': password,
20+
});
21+
22+
// ATTENTION: For everything except the Login Process.
23+
export const getAuthenticationHeaders = (userId, token) => ({
24+
'Authentication-User-Id': userId,
25+
'Authentication-Token': token,
26+
});
27+
28+
export const handleHTTPErrors = (response) => {
29+
if (!response.ok) {
30+
throw Error(response.statusText);
31+
}
32+
33+
return response;
34+
};

projectforge-webapp/yarn.lock

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2505,7 +2505,7 @@ cookie-signature@1.0.6:
25052505
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
25062506
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
25072507

2508-
cookie@0.3.1:
2508+
cookie@0.3.1, cookie@^0.3.1:
25092509
version "0.3.1"
25102510
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
25112511
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
@@ -8148,6 +8148,14 @@ react-app-polyfill@^0.2.1:
81488148
raf "3.4.1"
81498149
whatwg-fetch "3.0.0"
81508150

8151+
react-cookies@^0.1.0:
8152+
version "0.1.0"
8153+
resolved "https://registry.yarnpkg.com/react-cookies/-/react-cookies-0.1.0.tgz#6bb883f2d1a397f138a4110300b46fe25df8f1a9"
8154+
integrity sha1-a7iD8tGjl/E4pBEDALRv4l348ak=
8155+
dependencies:
8156+
cookie "^0.3.1"
8157+
object-assign "^4.1.1"
8158+
81518159
react-dev-utils@^7.0.3:
81528160
version "7.0.3"
81538161
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-7.0.3.tgz#f1316cfffd792fd41b0c28ad5db86c1d74484d6f"

0 commit comments

Comments
 (0)