jwt auth workflow
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.0",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
@@ -1,51 +1,73 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Home from './pages/Home'
|
||||
import jwt_decode from "jwt-decode";
|
||||
import API from './util/API';
|
||||
import './App.css'
|
||||
import Auth from './pages/Auth';
|
||||
import './App.css'
|
||||
|
||||
function App() {
|
||||
const [user, setUser] = useState(null);
|
||||
const [contents, setContents] = useState();
|
||||
const [contents, setContents] = useState(<></>);
|
||||
|
||||
useEffect(() => {
|
||||
(async() => {
|
||||
const res = await API.validate();
|
||||
console.log(res);
|
||||
async function handleLogin(info) {
|
||||
if (!info.email || !info.password) return;
|
||||
|
||||
if (res.user) {
|
||||
setUser(res.user);
|
||||
} else {
|
||||
setUser(null);
|
||||
}
|
||||
})();
|
||||
}, [])
|
||||
const response = await API.login(info);
|
||||
console.log(response);
|
||||
|
||||
useEffect(() => {
|
||||
setContents(user ? <Home user={user} handleLogout={handleLogout} /> : <Auth handleLogin={handleLogin} handleRegister={handleRegister} />);
|
||||
}, [user]);
|
||||
const user = jwt_decode(response.token);
|
||||
console.log(user);
|
||||
|
||||
localStorage.setItem('user', JSON.stringify(user));
|
||||
localStorage.setItem('token', response.token);
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
await API.logout();
|
||||
setUser(null);
|
||||
localStorage.removeItem("user");
|
||||
localStorage.removeItem("token");
|
||||
}
|
||||
|
||||
async function handleLogin(info) {
|
||||
const res = await API.login(info);
|
||||
if (res.data) setUser(res.data);
|
||||
return;
|
||||
async function handleRegister(register) {
|
||||
if (!register.username || !register.email || !register.password) return;
|
||||
await API.register(register);
|
||||
}
|
||||
|
||||
async function handleRegister(info) {
|
||||
const res = await API.register(info);
|
||||
console.log(res);
|
||||
return;
|
||||
}
|
||||
useEffect(() => {
|
||||
let item = localStorage.getItem('user');
|
||||
if (item) {
|
||||
item = JSON.parse(item);
|
||||
setUser(item.user);
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let protectedData;
|
||||
|
||||
if (user) {
|
||||
(async() => {
|
||||
protectedData = await API.getItems();
|
||||
console.log(protectedData);
|
||||
})();
|
||||
}
|
||||
|
||||
setContents(
|
||||
user ? (
|
||||
<div>
|
||||
<p>Welcome, {user.username}!</p>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<button onClick={handleLogout}>Log Out</button>
|
||||
</div>
|
||||
) : (
|
||||
<Auth handleLogin={handleLogin} handleRegister={handleRegister} />
|
||||
)
|
||||
)
|
||||
}, [user])
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1>Auth Testing</h1>
|
||||
|
||||
{ contents }
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,52 +1,17 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { LoginForm, RegisterForm } from "../components/Form";
|
||||
|
||||
function Auth({ handleLogin, handleRegister }) {
|
||||
const [info, setInfo] = useState({ username: "", email: "", password: "" });
|
||||
const [mode, setMode] = useState("login");
|
||||
const [form, setForm] = useState(<LoginForm info={info} setInfo={setInfo} />);
|
||||
const [button, setButton] = useState(
|
||||
<>
|
||||
<button onClick={() => handleLogin(info)}>Login</button>
|
||||
<aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside>
|
||||
</>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(mode);
|
||||
}, [info]);
|
||||
|
||||
function swapForm() {
|
||||
if (mode === "register") {
|
||||
setMode("login");
|
||||
setForm(<LoginForm info={info} setInfo={setInfo} />);
|
||||
setButton(
|
||||
<>
|
||||
<button onClick={() => handleLogin(info)}>Login</button>
|
||||
<aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
setMode("register");
|
||||
setForm(<RegisterForm info={info} setInfo={setInfo} />);
|
||||
setButton(
|
||||
<>
|
||||
<button onClick={() => handleRegister(info)}>Register</button>
|
||||
<aside>Looking for the login section? Click <a onClick={swapForm}>here</a></aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
const [info, setInfo] = useState({ email: "", password: "" });
|
||||
const [register, setRegister] = useState({ username: "", email: "", password: "" })
|
||||
|
||||
return (
|
||||
<section>
|
||||
<LoginForm info={info} setInfo={setInfo} />
|
||||
<button onClick={() => handleLogin(info)}>Login</button>
|
||||
{/* <aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside> */}
|
||||
|
||||
<RegisterForm info={info} setInfo={setInfo} />
|
||||
<button onClick={() => handleRegister(info)}>Register</button>
|
||||
{/* <aside>Looking for the login section? Click <a onClick={swapForm}>here</a></aside> */}
|
||||
<RegisterForm info={register} setInfo={setRegister} />
|
||||
<button onClick={() => handleRegister(register)}>Register</button>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,19 +5,6 @@ function Home({ user, handleLogout }) {
|
||||
const [items, setItems] = useState(null);
|
||||
console.log(user);
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
(async() => {
|
||||
const myItems = await API.getItems();
|
||||
|
||||
setItems(myItems.map(each => <>{each.id}</>));
|
||||
})();
|
||||
} else {
|
||||
setItems(null);
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
async function getStatus() {
|
||||
const res = await API.validate();
|
||||
console.log(res);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import axiosInstance from './axiosInstance';
|
||||
const _api = axiosInstance();
|
||||
import { default as _api } from './axiosInstance';
|
||||
|
||||
export default class API {
|
||||
static async validate() {
|
||||
@@ -42,7 +41,14 @@ export default class API {
|
||||
}
|
||||
|
||||
static async getItems() {
|
||||
const response = await _api.get('/app/item');
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
const response = await _api.get('/app/item', {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": ("Bearer " + token)
|
||||
}
|
||||
});
|
||||
return Promise.resolve(response.data);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,6 @@ import axios from 'axios'
|
||||
|
||||
const apiUrl = import.meta.env.VITE_APIURL;
|
||||
|
||||
export default function axiosInstance() {
|
||||
if (!apiUrl) {
|
||||
throw new Error("API URL not found");
|
||||
}
|
||||
|
||||
return axios.create({ baseURL: apiUrl });
|
||||
}
|
||||
export default axios.create({
|
||||
baseURL: "http://localhost:8080"
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
const passport = require('passport');
|
||||
const { Strategy } = require('passport-local');
|
||||
const AuthController = require('../controllers/authController');
|
||||
const JwtStrategy = require('passport-jwt').Strategy;
|
||||
const { ExtractJwt } = require('passport-jwt');
|
||||
|
||||
async function passportLoader(app) {
|
||||
app.use(passport.initialize());
|
||||
@@ -18,24 +18,20 @@ async function passportLoader(app) {
|
||||
})
|
||||
})
|
||||
|
||||
passport.use(new Strategy({ usernameField: "email", passwordField: "password" }, async (email, password, done) => {
|
||||
console.log('calling local strategy');
|
||||
console.log(email, password);
|
||||
// config for jwt strategy
|
||||
let opts = {
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: 'secret'
|
||||
}
|
||||
|
||||
// jwt strategy
|
||||
passport.use(new JwtStrategy(opts, async (token, done) => {
|
||||
try {
|
||||
console.log('before response')
|
||||
const response = await AuthController.login({ email: email, password: password });
|
||||
console.log(response);
|
||||
|
||||
if (response && response.ok) {
|
||||
return done(null, response.data.data);
|
||||
} else {
|
||||
return done(null, false);
|
||||
}
|
||||
return done(null, token.user);
|
||||
} catch (error) {
|
||||
return done(error);
|
||||
done(error);
|
||||
}
|
||||
}))
|
||||
}));
|
||||
|
||||
return passport;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"express-session": "^1.17.3",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"passport": "^0.6.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^8.9.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
const AuthController = require('../controllers/authController');
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const router = require('express').Router();
|
||||
require('dotenv').config();
|
||||
|
||||
const secret = process.env.SECRET;
|
||||
|
||||
async function authRoute(app, passport) {
|
||||
router.post('/register', async (req, res) => {
|
||||
@@ -17,18 +20,36 @@ async function authRoute(app, passport) {
|
||||
router.post('/login', passport.authenticate('local'), async (req, res, next) => {
|
||||
try {
|
||||
const data = req.body;
|
||||
const response = await AuthController.login(data);
|
||||
let response = await AuthController.login(data);
|
||||
|
||||
if (!response || !response.ok) {
|
||||
res.status(response.code || 400).send(response.data || "Something went wrong");
|
||||
} else {
|
||||
req.user = response.data;
|
||||
req.session.user = response.data;
|
||||
// flatten controller responses
|
||||
while (response.data) {
|
||||
response = response.data;
|
||||
}
|
||||
|
||||
req.user = response;
|
||||
req.session.user = response;
|
||||
|
||||
// exclude sensitive data from being stored client side
|
||||
const safeUserData = {
|
||||
id: response.id,
|
||||
username: response.username,
|
||||
email: response.email,
|
||||
created: response.created,
|
||||
modified: response.modified
|
||||
}
|
||||
|
||||
const token = jwt.sign({ user: safeUserData }, secret);
|
||||
req.session.token = token;
|
||||
|
||||
req.session.save((err) => {
|
||||
return next(err);
|
||||
})
|
||||
|
||||
res.send(response.data);
|
||||
res.json({ token });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
|
||||
@@ -2,15 +2,6 @@ const authRoute = require("./auth");
|
||||
const itemRoute = require("./item");
|
||||
|
||||
async function routesLoader(app, passport) {
|
||||
app.use('/', (req, res, next) => {
|
||||
console.log(req.user || "no user");
|
||||
next();
|
||||
})
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.send(req.session);
|
||||
})
|
||||
|
||||
app.use('/auth', await authRoute(app, passport));
|
||||
app.use('/app', await itemRoute(app, passport));
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
require('dotenv').config();
|
||||
const router = require('express').Router();
|
||||
const ItemController = require('../controllers/ItemController');
|
||||
|
||||
function itemRoute(app, passport) {
|
||||
async function itemRoute(app, passport) {
|
||||
router.use('/', (req, res, next) => {
|
||||
if (req.user == null) {
|
||||
res.status(403).send("Unauthorized");
|
||||
return;
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
console.log('check for jwt');
|
||||
const token = req.headers['authorization'].split(" ")[1];
|
||||
jwt.verify(token, process.env.SECRET, (err, data) => {
|
||||
if (err) {
|
||||
res.status(403).send(err);
|
||||
} else {
|
||||
req.user = data;
|
||||
next();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
router.get('/item', async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user