mirror of
https://github.com/ThisIsBenny/wishlist-app.git
synced 2025-04-19 15:27:41 +00:00
#3 protect endpoints via API-Key
Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de>
This commit is contained in:
parent
b7c1caebd7
commit
bb5099d7d4
9 changed files with 67 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
|||
NODE_ENV=development
|
||||
VITE_API_BASEURL=http://localhost:5000/api
|
||||
DATABASE_URL="file:../data/data.db"
|
||||
API_KEY=TOP_SECRET
|
||||
|
|
|
@ -3,6 +3,8 @@ version: '3.7'
|
|||
services:
|
||||
wishlist:
|
||||
image: thisisbenny/wishlist-app:latest
|
||||
environment:
|
||||
- API_KEY=TOP_SECRET
|
||||
ports:
|
||||
- '5000:5000'
|
||||
volumes:
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# @name createWishlistFirst
|
||||
POST {{BASE_URL}}/wishlist
|
||||
Content-Type: application/json
|
||||
Authorization: API-Key TOP_SECRET
|
||||
|
||||
{
|
||||
"title": "Junior",
|
||||
|
|
36
src/api/config/auth.ts
Normal file
36
src/api/config/auth.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'
|
||||
import { notAuthorized } from './errors'
|
||||
|
||||
const error = notAuthorized('Unauthorized')
|
||||
|
||||
export default {
|
||||
init: async (app: FastifyInstance) => {
|
||||
if (!process.env.API_KEY) {
|
||||
throw new Error('ENV API_KEY is not set!')
|
||||
}
|
||||
app.addHook(
|
||||
'onRequest',
|
||||
(request: FastifyRequest, reply: FastifyReply, done) => {
|
||||
//@ts-expect-error: custom attribute
|
||||
if (!reply.context.config.protected) {
|
||||
return done()
|
||||
}
|
||||
if (!request.headers.authorization) {
|
||||
return done(error)
|
||||
}
|
||||
const authHeader = request.headers.authorization.split(' ')
|
||||
request.log.debug(authHeader)
|
||||
if (
|
||||
authHeader[0] &&
|
||||
authHeader[0].trim().toLowerCase() === 'api-key' &&
|
||||
authHeader[1]
|
||||
) {
|
||||
if (authHeader[1] === process.env.API_KEY) {
|
||||
return done()
|
||||
}
|
||||
}
|
||||
done(error)
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
|
@ -21,6 +21,8 @@ export const defaultErrorHandler = (
|
|||
)
|
||||
} else if (errorIs(error, 'P2025')) {
|
||||
reply.callNotFound()
|
||||
} else if (error instanceof httpError) {
|
||||
reply.send(error)
|
||||
} else {
|
||||
request.log.error(error)
|
||||
const e = new httpError('unexpected error', 500, '500')
|
||||
|
@ -47,10 +49,13 @@ class httpError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
const notFoundError = () => {
|
||||
export const notFoundError = () => {
|
||||
return new httpError('Not Found', 404, '404')
|
||||
}
|
||||
|
||||
const uniqueKeyError = (msg: string, code = '4001') => {
|
||||
export const uniqueKeyError = (msg: string, code = '4001') => {
|
||||
return new httpError(msg, 422, code)
|
||||
}
|
||||
export const notAuthorized = (msg: string, code = '401') => {
|
||||
return new httpError(msg, 401, code)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import Fastify, { FastifyContextConfig } from 'fastify'
|
|||
import compress from 'fastify-compress'
|
||||
import cors from 'fastify-cors'
|
||||
import { fastify as defaultConfig } from './'
|
||||
import auth from './auth'
|
||||
|
||||
export default async (opts: FastifyContextConfig = {}) => {
|
||||
const app = Fastify({
|
||||
|
@ -23,6 +24,7 @@ export default async (opts: FastifyContextConfig = {}) => {
|
|||
})
|
||||
|
||||
await app.register(compress)
|
||||
await auth.init(app)
|
||||
|
||||
return app
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ interface createItemRequest extends FastifyRequest {
|
|||
export const createList = <RouteOptions>{
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
body: wishlistRequestSchema,
|
||||
response: {
|
||||
|
@ -33,6 +36,9 @@ export const createList = <RouteOptions>{
|
|||
export const createItem = <RouteOptions>{
|
||||
method: 'POST',
|
||||
url: '/:wishlistId/item',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
body: wishlistItemRequestSchema,
|
||||
params: {
|
||||
|
|
|
@ -17,6 +17,9 @@ interface deleteItemRequest extends FastifyRequest {
|
|||
export const deleteList = <RouteOptions>{
|
||||
method: 'DELETE',
|
||||
url: '/:wishlistId',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
|
@ -34,6 +37,9 @@ export const deleteList = <RouteOptions>{
|
|||
export const deleteItem = <RouteOptions>{
|
||||
method: 'DELETE',
|
||||
url: '/:wishlistId/item/:itemId',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
|
|
|
@ -24,6 +24,9 @@ interface updateItemRequest extends FastifyRequest {
|
|||
export const updateList = <RouteOptions>{
|
||||
method: 'PUT',
|
||||
url: '/:wishlistId',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
body: wishlistRequestSchema,
|
||||
params: {
|
||||
|
@ -49,6 +52,9 @@ export const updateList = <RouteOptions>{
|
|||
export const updateItem = <RouteOptions>{
|
||||
method: 'PUT',
|
||||
url: '/:wishlistId/item/:itemId',
|
||||
config: {
|
||||
protected: true,
|
||||
},
|
||||
schema: {
|
||||
body: wishlistItemRequestSchema,
|
||||
params: {
|
||||
|
|
Loading…
Add table
Reference in a new issue