More specific access control headers to support cross origin Authorization
Pretty sign in page Verify existing JWT on application mount
This commit is contained in:
@ -29,11 +29,13 @@ export function fetchLoginRedirect() {
|
||||
/**
|
||||
* Wraps the normal fetch routene with one with provides the access token if present.
|
||||
*/
|
||||
export function secureFetch(url, params) {
|
||||
if (localStorage.getItem(ACCESS_TOKEN)) {
|
||||
export function authorizedFetch(url, params) {
|
||||
const accessToken = localStorage.getItem(ACCESS_TOKEN);
|
||||
if (accessToken) {
|
||||
params = params || {};
|
||||
params.headers = params.headers || new Headers();
|
||||
params.headers.Authorization = 'Bearer ' + localStorage.getItem(ACCESS_TOKEN)
|
||||
params.credentials = 'include';
|
||||
params.headers = params.headers || {};
|
||||
params.headers.Authorization = 'Bearer ' + accessToken;
|
||||
}
|
||||
return fetch(url, params);
|
||||
}
|
||||
@ -41,9 +43,9 @@ export function secureFetch(url, params) {
|
||||
/**
|
||||
* Wraps the normal fetch routene which redirects on 401 response.
|
||||
*/
|
||||
export function redirectingSecureFetch(url, params) {
|
||||
export function redirectingAuthorizedFetch(url, params) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
secureFetch(url, params).then(response => {
|
||||
authorizedFetch(url, params).then(response => {
|
||||
if (response.status === 401) {
|
||||
history.go("/");
|
||||
} else {
|
||||
|
@ -1,10 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import history from '../history'
|
||||
import { withNotifier } from '../components/SnackbarNotification';
|
||||
|
||||
import { ACCESS_TOKEN } from './Authentication';
|
||||
import { VERIFY_AUTHORIZATION_ENDPOINT } from '../constants/Endpoints';
|
||||
import { ACCESS_TOKEN, authorizedFetch } from './Authentication';
|
||||
import { AuthenticationContext } from './Context';
|
||||
import jwtDecode from 'jwt-decode';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
const styles = theme => ({
|
||||
loadingPanel: {
|
||||
padding: theme.spacing.unit * 2,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "100vh",
|
||||
flexDirection: "column"
|
||||
},
|
||||
progress: {
|
||||
margin: theme.spacing.unit * 4,
|
||||
}
|
||||
});
|
||||
|
||||
class AuthenticationWrapper extends React.Component {
|
||||
|
||||
@ -44,23 +61,30 @@ class AuthenticationWrapper extends React.Component {
|
||||
}
|
||||
|
||||
renderContentLoading() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>THIS IS WHERE THE LOADING MESSAGE GOES</div>
|
||||
<div className={classes.loadingPanel}>
|
||||
<CircularProgress className={classes.progress} size={100} />
|
||||
<Typography variant="h4" >
|
||||
Loading...
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
var accessToken = localStorage.getItem(ACCESS_TOKEN);
|
||||
if (accessToken) {
|
||||
try {
|
||||
this.setState({ initialized: true, context: { ...this.state.context, jwt: jwtDecode(accessToken) } });
|
||||
} catch (err) {
|
||||
localStorage.removeItem(ACCESS_TOKEN);
|
||||
this.props.raiseNotification("Please log in again.");
|
||||
history.push('/');
|
||||
}
|
||||
authorizedFetch(VERIFY_AUTHORIZATION_ENDPOINT)
|
||||
.then(response => {
|
||||
const jwt = response.status === 200 ? jwtDecode(accessToken) : undefined;
|
||||
this.setState({ initialized: true, context: { ...this.state.context, jwt } });
|
||||
}).catch(error => {
|
||||
this.setState({ initialized: true, context: { ...this.state.context, jwt: undefined } });
|
||||
this.props.raiseNotification("Error verifying authorization: " + error.message);
|
||||
});
|
||||
} else {
|
||||
this.setState({ initialized: true });
|
||||
this.setState({ initialized: true, context: { ...this.state.context, jwt: undefined } });
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,8 +93,8 @@ class AuthenticationWrapper extends React.Component {
|
||||
this.setState({ context: { ...this.state.context, jwt: jwtDecode(accessToken) } });
|
||||
localStorage.setItem(ACCESS_TOKEN, accessToken);
|
||||
} catch (err) {
|
||||
this.props.raiseNotification("JWT did not parse.");
|
||||
history.push('/');
|
||||
this.setState({ initialized: true, context: { ...this.state.context, jwt: undefined } });
|
||||
this.props.raiseNotification("Failed to parse JWT " + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +103,7 @@ class AuthenticationWrapper extends React.Component {
|
||||
this.setState({
|
||||
context: {
|
||||
...this.state.context,
|
||||
me: undefined
|
||||
jwt: undefined
|
||||
}
|
||||
});
|
||||
this.props.raiseNotification("You have signed out.");
|
||||
@ -88,4 +112,4 @@ class AuthenticationWrapper extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
export default withNotifier(AuthenticationWrapper)
|
||||
export default withStyles(styles)(withNotifier(AuthenticationWrapper))
|
||||
|
Reference in New Issue
Block a user