Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* Support sign out

* Adds 'Sign out' button
* `GET /scg-logout` request made to set required CSRF cookie
* `POST /scg-logout` CSRF-enabled request made to sign out of Gateway
* Application state reset

* Use axios instead of fetch, configure local run, add e2e test

Co-authored-by: Yuxin Bai <LittleBaiBai@users.noreply.github.com>
  • Loading branch information
spikymonkey and LittleBaiBai authored Mar 5, 2020
1 parent afb15be commit 900ddd9
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 31 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PATH_add scripts
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Some other commands that might be helpful:
The frontend application is implemented in ReactJS, and is pushed with static buildpack. Because of it's static nature, we had to do the following
1. `homepage` in `package.json` is set to `/rescue`, which is the path we set for the frontend application in gateway config (`frontend/gateway-config.json`). This is to make sure all related assets is requested under `/rescue` path as well.
1. `Sign in to adopt` button is linked to `/rescue/login`, which is a path that is `sso-enabled` in gateway config (`frontend/gateway-config.json`). This is necessary for frontend apps bound to a sub path on gateway because the Oauth2 login flow redirects users to the original requested location or back to `/` if no saved request exists. This setting is not necessary if the frontend app is bound to path `/`.
1. `REACT_APP_BACKEND_BASE_URL` is set to `/backend` in build script, which is the path we set for the backend application in gateway config (`backend/gateway-config.json`). This is to make sure all our backend API calls are appended with the `backend` path.
1. `REACT_APP_BACKEND_BASE_URI` is set to `/backend` in build script, which is the path we set for the backend application in gateway config (`backend/gateway-config.json`). This is to make sure all our backend API calls are appended with the `backend` path.


## Try it out
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.spring.cloud.samples.animalrescue.backend;

import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
Expand Down
5 changes: 5 additions & 0 deletions e2e/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
5 changes: 5 additions & 0 deletions e2e/cypress/integration/rescue.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ context('Animal Rescue', () => {
});
});

it('allows user to log out', () => {
cy.contains('Sign out').click();
cy.contains('Sign in to adopt');
});

const logIn = (username, password) => {
cy.get('input[name=username]').type(username);
cy.get('input[name=password]').type(`${password}{enter}`); // {enter} causes the form to submit
Expand Down
6 changes: 4 additions & 2 deletions frontend/gateway-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
{
"path": "/rescue/admin,/rescue/login",
"sso-enabled": true,
"filters": ["RedirectTo=302, /rescue"]
"filters": ["RedirectTo=302, /rescue"],
"order": 0
},
{
"path": "/rescue/**"
"path": "/rescue/**",
"order": 1000
}
]
}
4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"semantic-ui-react": "^0.88.2"
},
"scripts": {
"start": "wait-on tcp:8080 && REACT_APP_LOGIN_PATH=http://localhost:8080/login react-scripts start",
"build": "REACT_APP_BACKEND_BASE_URL=/api react-scripts build",
"start": "wait-on tcp:8080 && REACT_APP_LOGIN_URI=http://localhost:8080/login REACT_APP_LOGOUT_URI=/logout react-scripts start",
"build": "REACT_APP_BACKEND_BASE_URI=/api react-scripts build",
"lint": "eslint src",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand Down
Binary file removed frontend/public/slider-background.jpg
Binary file not shown.
9 changes: 1 addition & 8 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,6 @@
margin: 10px 0 50px;
}

.slider-wrapper {
background: url('/slider-background.jpg');
background-position: center;
background-size: 100%;
height: 100%;
}

.carousel .slide {
background: transparent;
}
Expand All @@ -186,4 +179,4 @@
width: 100% ;
vertical-align: middle;
}
}
}
34 changes: 27 additions & 7 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import './App.css';
import logo from './logo.svg';
import AnimalCards from "./components/animal-cards";
import Carousel from "./components/carousel";
import {getAnimals, getUsername} from "./httpClient";
import {getAnimals, getUsername, logoutFromGateway} from "./httpClient";
import {AppContext} from "./AppContext";

const PENDING = 'pending', AUTHENTICATED = 'authenticated', ANONYMOUS = 'anonymous';

export default class App extends React.Component {

#loginLink = process.env.REACT_APP_LOGIN_PATH || '/rescue/login';
#loginLink = process.env.REACT_APP_LOGIN_URI || '/rescue/login';

constructor(props, context) {
super(props, context);
Expand All @@ -34,6 +34,13 @@ export default class App extends React.Component {
}));
};

logout = () => {
logoutFromGateway().then(_ => this.setState({
username: '',
userStatus: ANONYMOUS,
}));
};

componentDidMount() {
this.fetchAnimals();
this.getUsername();
Expand All @@ -45,6 +52,7 @@ export default class App extends React.Component {
<header className="App-header">
<img src={logo} title="Logo" width="250" alt="Logo"/>
<div className="header-buttons">
{this.getGreetButton()}
{this.getActionButton()}
</div>
</header>
Expand All @@ -59,15 +67,27 @@ export default class App extends React.Component {
);
}

getGreetButton() {
switch (this.state.userStatus) {
case ANONYMOUS:
return <Button disabled color='green' basic> Let meow greet ya! </Button>;
case AUTHENTICATED:
return <Button disabled color='green' basic> Have a cute day {this.state.username}! </Button>;
default:
return <div/>;
}
}
getActionButton() {
switch (this.state.userStatus) {
case ANONYMOUS:
return (<Button animated='fade' color='green' href={this.#loginLink}>
<Button.Content visible>Sign in to adopt</Button.Content>
<Button.Content hidden>It only takes a loving heart</Button.Content>
</Button>);
return (
<Button animated='fade' color='green' href={this.#loginLink}>
<Button.Content visible>Sign in to adopt</Button.Content>
<Button.Content hidden>It only takes a loving heart</Button.Content>
</Button>
);
case AUTHENTICATED:
return <Button disabled> Have a cute day {this.state.username}! </Button>;
return <Button color='green' onClick={this.logout}>Sign out</Button>;
default:
return <div/>;
}
Expand Down
33 changes: 26 additions & 7 deletions frontend/src/httpClient.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from 'axios';

const backendBaseUrl = process.env.REACT_APP_BACKEND_BASE_URL || '';
const backendBaseUrl = process.env.REACT_APP_BACKEND_BASE_URI || '';
const logoutUrl = process.env.REACT_APP_LOGOUT_URI || '/scg-logout';

export async function getAnimals() {
return axios
Expand All @@ -22,12 +23,30 @@ export async function deleteAdoptionRequest({animalId, adoptionRequestId}) {
}

export async function getUsername() {
return fetch(`${backendBaseUrl}/whoami`).then(r => {
if (r.redirected) {
return axios
.get(`${backendBaseUrl}/whoami`)
.then(res => {
if (res.request.responseURL && !res.request.responseURL.endsWith('whoami')) {
return '';
}
return res.data;
})
.catch(err => {
console.error('Failed to fetched username', err);
return '';
} else {
return r.text();
}
});
});
}

export async function logoutFromGateway() {
// Fetch and set the csrf cookie
await axios(logoutUrl);

// Pass cookie value in defined Gateway CSRF header
let csrfToken = document.cookie.replace(/.*\bSCG-XSRF-TOKEN=([^;]+).*/, "$1");

return axios.post(logoutUrl, null, {
headers: {
"X-SCG-XSRF-TOKEN": csrfToken,
},
});
}
4 changes: 2 additions & 2 deletions scripts/local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ startFrontend() {
stopBackend() {
if lsof -i:8080 -t &> /dev/null; then
printf "\n======== Stopping backend ========\n"
kill "$(lsof -i:8080 -t)"
pkill java
fi
}

Expand Down Expand Up @@ -103,7 +103,7 @@ e2e)
;;
start)
start "${2:-}"
if [[ $1 != "$QUIET_MODE" ]]; then
if [[ ${2:-} != "$QUIET_MODE" ]]; then
wait
fi
;;
Expand Down

0 comments on commit 900ddd9

Please sign in to comment.