- Navigate to the
\frontendfolder and runnpm install.
- Open the
\backendfolder in IntelliJ (or another IDEA of your choice). This is required for the IntelliJ to recognize the Gradle project to run. - Modify or Add a gitignore
- Create a
.gitignorefile exists in the\backenddirectory folder if one does not exist. - Add the following statement to the bottom of the file:
- Create a
### JWT TOKEN ###
*src/main/java/com/discovermotrails/securitybackend/constants/SecurityConstants.java- Create the JWT Key
- Inside
com.discovermotrails.securitybackend, create aconstantspackage. - Inside the
constantspackage create an interface with the file name:SecurityConstantswith the code below:- NOTE: IntelliJ will ask if you want to stage the file to commit to Git. DO NOT DO THIS. The
.gitignoreensures this file and the authorization key inside of it is not tracked.
- NOTE: IntelliJ will ask if you want to stage the file to commit to Git. DO NOT DO THIS. The
- Don't forget to import the
SecurityConstantsclass into both theJWTTokenGeneratorFilterandJWTTokenValidatorFilter
- Inside
package com.discovermotrails.securitybackend.constants;
public interface SecurityConstants {
public static final String JWT_KEY = "[FILL WITH YOUR OWN STRING OF AT LEAST 38 RANDOM CHARACTERS]";
public static final String JWT_HEADER = "Authorization";
}- Set the runtime environmental variables
- Open the right hand
Gradletab and double clickbootRun. The build will fail, and this is okay. - In the upper right hand corner, next to the play button, click on the dropdown and select
Edit Configurations.... - Establish variables for:
DB_HOSTNAME,DB_PORT,DB_DATABASE,DB_USER,DB_PASSWORD.- Having trouble setting environmental variables? Refer to this documentation from LaunchCode.
- This backend/frontend combination can work with locally stored MySQL database instances and those in AWS.
- Open the right hand
- The project should compile and run correctly on
http://localhost:8080.
This project uses basic authentication for non-logged in users and issues a JWT (JSON Web Token) on a successful login that the React frontend stores as a cookie. On subsequent requests to a page secured by the backend, the frontend sends the JWT Authorization in place of a user having to provide their login credentials again. Tokens are valid for about 8 hours and are set to expire on both the frontend and backend.
- Adjust this timing on the backend by updating the
.setExpiration()method contained in theJTWTokenGeneratorFilter.javaclass. - Adjust this timing on the frontend by updating
{maxAge: }in thesetCookie()method inauth.jsx. JWTs can be stored in localStorage on the frontend, however this is not encouraged because it comes with security risks.
The frontend achieves user authentication by making a GET request to /user, and passing a username and password using the auth header provided
by axios. The backend requires the passed username be an email.
axios.get(LOGIN_URL, { //LOGIN_URL = '/user'
auth: {
username: "[email protected]",
password: "user-password"
}
}The user's information will be loaded into the frontend's userContext and localStorage if the GET request is successful. An 'Authorization' cookie is also established with the JWT.
New users to the site can register to log in by making a POST request to /register. The body of this request should contain a JSON object containing
the fields for displayName, email, password and role (which is assigned automatically by the frontend).
{
"displayName": "User-display-name",
"email": "[email protected]",
"pwd": "user-password"
}Once a user is registered into the database, they will be able to log in using the login link in the nav bar. A successful login will return a page listing the user's ID number, username and email.
A failed login will return Invalid Credentials on the login form.
Alternatively you can test with Postman by sending a GET request to the http://localhost:8080/user api providing a registered email and password and selecting the Basic Auth under the authorization tab.
The website's main router is located in frontend/src/App.js.
- Import your component
- Define a route to the component inside
function App()using the following template:<Route path="[YOUR PATH NAME]" exact element={<[YOUR COMPONENT NAME]/>} - If your component needs to be behind our authentication wall it needs to be wrapped by a
<Protected></Protected>component. The code for that looks like this:
<Route
path="/[YOUR SECURED PATH]"
element={
<Protected>
<[YOUR SECURED COMPONENT] />
</Protected>
}
/>- Be sure to update the ProjectSecurityConfig.java file in
backend/src/main/java/com.discovermotrails.securitybackend/config.- Add secured paths to the comma separated list in the
.requestMatchers("/account","/user", "/secure").authenticated()method - Add public paths to the comma separated list in the
.requestMatchers("/index", "/register").permitAll()mehtod
- Add secured paths to the comma separated list in the
...
.authorizeHttpRequests()
.requestMatchers("/account","/user", "/secure").authenticated() // ADD SECURED PATHS HERE
.requestMatchers("/index", "/register").permitAll() // ADD PUBLIC PATHS HERE
.and().httpBasic();
return http.build();- You may also add a link to your component in the header in react. Open the
frontend/src/components/header/header.jsxfile and add a new<li>to the<nav>like this:
<li>
<Link to="[YOUR PATH]">[NAV LINK NAME]</Link>
</li>