reject posts route if token is invalid and send one on login
This commit is contained in:
parent
ece8da877a
commit
3261158588
|
|
@ -5,7 +5,7 @@ generator client {
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "mysql"
|
provider = "mysql"
|
||||||
url = env("DATABASE_URL")
|
url = env("DB_URL")
|
||||||
referentialIntegrity = "prisma"
|
referentialIntegrity = "prisma"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { getUser } from '@/controller/UserController';
|
import { getUser } from '@/controller/UserController';
|
||||||
import UserLoginModel from '@/models/UserLoginModel';
|
import UserLoginModel from '@/models/UserLoginModel';
|
||||||
import { comparePassword } from '@/controller/AuthController';
|
import { comparePassword, genToken } from '@/controller/AuthController';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { User } from '@prisma/client';
|
import { User } from '@prisma/client';
|
||||||
|
|
||||||
|
|
@ -15,7 +15,8 @@ const login = async (req: Request, res: Response) => {
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
return res.status(401).send({ error: 'Invalid password' });
|
return res.status(401).send({ error: 'Invalid password' });
|
||||||
}
|
}
|
||||||
return res.status(200).send(user);
|
const token = genToken(user.id);
|
||||||
|
return res.status(200).send({ token, userId: user.id });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(500).send(error);
|
return res.status(500).send(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,37 @@
|
||||||
import { Router } from 'express';
|
import { NextFunction, Request, Response, Router } from 'express';
|
||||||
import getPosts from './getPosts';
|
import getPosts from './getPosts';
|
||||||
import postPost from './newPost';
|
import postPost from './newPost';
|
||||||
import putPost from './editPost';
|
import putPost from './editPost';
|
||||||
import deletePost from './deletePost';
|
import deletePost from './deletePost';
|
||||||
import likePost from './likePost';
|
import likePost from './likePost';
|
||||||
import unlikePost from './unlikePost';
|
import unlikePost from './unlikePost';
|
||||||
|
import { verifyToken } from '@/controller/AuthController';
|
||||||
|
import { Token } from '@/models/TokenModel';
|
||||||
|
|
||||||
const posts = Router();
|
const posts = Router();
|
||||||
|
|
||||||
|
const getToken = (req: Request): string | undefined => {
|
||||||
|
const token: string | undefined = req.headers.authorization?.substring(7); // remove 'Bearer ' from token
|
||||||
|
return token;
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkAuth = (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const token = getToken(req);
|
||||||
|
if (token === undefined) {
|
||||||
|
return res.status(401).send('No token provided');
|
||||||
|
}
|
||||||
|
return verifyToken(token)
|
||||||
|
.then((decodedToken: Token) => {
|
||||||
|
req.userId = decodedToken.id;
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return res.status(401).send('Invalid token');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
posts.use(checkAuth);
|
||||||
|
|
||||||
posts.get('/', getPosts);
|
posts.get('/', getPosts);
|
||||||
posts.post('/new', postPost);
|
posts.post('/new', postPost);
|
||||||
posts.put('/edit/:id', putPost);
|
posts.put('/edit/:id', putPost);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import * as jwt from 'jsonwebtoken';
|
import * as jwt from 'jsonwebtoken';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import * as dotenv from 'dotenv';
|
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
|
import { config } from '..';
|
||||||
dotenv.config();
|
import { Token } from '@/models/TokenModel';
|
||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
const hashPromise = promisify(bcrypt.hash);
|
const hashPromise = promisify(bcrypt.hash);
|
||||||
|
|
@ -16,4 +15,25 @@ const comparePassword = (password: string, hash: string) => {
|
||||||
return bcrypt.compare(password, hash);
|
return bcrypt.compare(password, hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { hashPassword, comparePassword };
|
const genToken = (id: number) => {
|
||||||
|
return jwt.sign({ id }, config.JWT_SECRET, {
|
||||||
|
expiresIn: config.JWT_EXPIRES_IN,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const verifyToken = (token: string): Promise<Token> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
jwt.verify(token, config.JWT_SECRET, (err?, decoded?: jwt.JwtPayload | string) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else if (decoded === undefined || typeof decoded === 'string' || decoded.id === undefined) {
|
||||||
|
reject('Invalid token');
|
||||||
|
} else {
|
||||||
|
const decodedToken: Token = { id: decoded.id };
|
||||||
|
resolve(decodedToken);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { hashPassword, comparePassword, genToken, verifyToken };
|
||||||
|
|
|
||||||
13
src/index.ts
13
src/index.ts
|
|
@ -1,9 +1,15 @@
|
||||||
import express, { urlencoded, json } from 'express';
|
import express, { urlencoded, json } from 'express';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import api from '@/api';
|
import api from '@/api';
|
||||||
import { config } from 'dotenv';
|
import { config as envConfig } from 'dotenv';
|
||||||
|
|
||||||
config();
|
envConfig();
|
||||||
|
|
||||||
|
interface Config {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let config: Config = {};
|
||||||
|
|
||||||
const checkEnvVars = () => {
|
const checkEnvVars = () => {
|
||||||
const requiredEnvVars = ['PORT', 'DB_URL', 'JWT_SECRET', 'JWT_EXPIRES_IN'];
|
const requiredEnvVars = ['PORT', 'DB_URL', 'JWT_SECRET', 'JWT_EXPIRES_IN'];
|
||||||
|
|
@ -12,6 +18,8 @@ const checkEnvVars = () => {
|
||||||
if (process.env[envVar] === undefined) {
|
if (process.env[envVar] === undefined) {
|
||||||
error = true;
|
error = true;
|
||||||
console.log(`${envVar} is undefined`);
|
console.log(`${envVar} is undefined`);
|
||||||
|
} else {
|
||||||
|
config[envVar] = process.env[envVar] as string;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
@ -20,6 +28,7 @@ const checkEnvVars = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
checkEnvVars();
|
checkEnvVars();
|
||||||
|
export { config };
|
||||||
|
|
||||||
const port = process.env.PORT || 5000;
|
const port = process.env.PORT || 5000;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
type Token = {
|
||||||
|
id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Token };
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export {};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace Express {
|
||||||
|
export interface Request {
|
||||||
|
userId?: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"module": "CommonJS",
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"esnext"
|
"esnext"
|
||||||
],
|
],
|
||||||
|
|
@ -23,7 +22,10 @@
|
||||||
"@@/*": [
|
"@@/*": [
|
||||||
"./*"
|
"./*"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"typeRoots": [
|
||||||
|
"src/types"
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"require": [
|
"require": [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue