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:
Rick Watson
2019-05-19 17:51:57 +01:00
parent 04e852f7d9
commit 396d0333b6
9 changed files with 102 additions and 70 deletions

View File

@ -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 {

View File

@ -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))