Terakhir diperbaharui: Jan 1, 2021
Implementasi sistem autentikasi - Proteksi API
Setelah membatasi akses untuk setiap halaman kita akan lanjutkan dengan membatasi setiap API endpoint yang dimiliki.
Hal ini dilakukan untuk menghindari pihak yang tidak bertanggung jawab menggunakan API endpoint yang bersifat terbuka atau publik.
Pembatasan ini dilakukan dengan cara untuk setiap request dari client yang dikirimkan ke API harus disertai dengan token sebagai bukti bahwa user yang mengirimkan request adalah user yang sudah memiliki akun atau sudah registrasi di aplikasi. Selain itu maka ditolak.
Step by step
Konfigurasi strategi JWT
Langkah ini dilakukan pada project dinotes-api dan bukan dinotes-client
Install package atau modul passport-jwt.
1yarn add passport-jwt
Tambahkan strategi untuk menangani autentikasi berbasis JWT:
utils/auth.js
1...2const passportJWT = require('passport-jwt');3const { ObjectId } = require('mongodb');45const JWTStrategy = passportJWT.Strategy;6const ExtractJWT = passportJWT.ExtractJwt;7...8passport.use(9 new JWTStrategy(10 {11 jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),12 secretOrKey: 'mys3cret'13 },14 async (payload, done) => {15 try {16 const db = getDb();17 const user = await db.collection('users').findOne({ _id: ObjectId(payload._id) });1819 if (!user) {20 return done(null, false);21 }2223 return done(null, user);24 } catch (error) {25 return done(error);26 }27 }28 )29);
Yang perlu diperhatikan disini adalah secret key yang digunakan untuk membongkar token haruslah sama dengan yang digunakan untuk membuat token. Dalam hal ini adalah string 'mys3cret'.
Proteksi API endpoint
Update routes.js dengan menambahkan passport sebagai middleware.
routes.js
1const express = require('express');2const passport = require('passport');34const router = express.Router();56const { addNote, getAllNotes, getNote, updateNote, deleteNote, register, login } = require('./handler');78require('./utils/auth');910// notes11router.post('/note', passport.authenticate('jwt', { session: false }), addNote);1213router.get('/notes', passport.authenticate('jwt', { session: false }), getAllNotes);1415router.get('/note/:id', passport.authenticate('jwt', { session: false }), getNote);1617router.put('/note/:id', passport.authenticate('jwt', { session: false }), updateNote);1819router.delete('/note/:id', passport.authenticate('jwt', { session: false }), deleteNote);2021// user22router.post('/register', register);2324router.post('/login', login);2526module.exports = router;
Setelah API endpoint diproteksi maka jika kita mengirim request tanpa token kita akan mendapat error message Unauthorized.
Menambah bearer token
Langkah terakhir adalah menambahkan token yang didapat dari localStorage ke setiap request yang dikirim ke API.
Token dikirim sebagai OAuth Bearer Token.
dinotes-client/features/notes/notesSlice.js
1...2const user = JSON.parse(localStorage.getItem('user'));34const initialState = {5 data: [],6 status: 'idle',7 error: null8};910export const fetchNotes = createAsyncThunk('notes/fetchNotes', async () => {11 const requestOptions = {12 method: 'GET',13 headers: {14 Authorization: `Bearer ${user.token}`,15 'Content-Type': 'application/json'16 }17 };1819 const response = await fetch(`${process.env.REACT_APP_API_URL}/notes`, requestOptions);20 if (response.ok) {21 const data = await response.json();22 return data;23 } else {24 throw Error(response.statusText);25 }26});2728export const addNewNote = createAsyncThunk('notes/AddNewNote', async (initialNotes) => {29 const requestOptions = {30 method: 'POST',31 headers: {32 Authorization: `Bearer ${user.token}`,33 'Content-Type': 'application/json'34 },35 body: JSON.stringify(initialNotes)36 };3738 const response = await fetch(`${process.env.REACT_APP_API_URL}/note`, requestOptions);39 if (response.ok) {40 const data = await response.json();41 const noteAdded = { ...initialNotes, _id: data._id };42 return noteAdded;43 } else {44 throw Error(response.statusText);45 }46});4748export const updateExistingNote = createAsyncThunk('notes/updateNote', async (currentNote) => {49 const requestOptions = {50 method: 'PUT',51 headers: { Authorization: `Bearer ${user.token}`, 'Content-Type': 'application/json' },52 body: JSON.stringify(currentNote)53 };5455 const response = await fetch(`${process.env.REACT_APP_API_URL}/note/${currentNote._id}`, requestOptions);56 if (response.ok) {57 return currentNote;58 } else {59 throw Error(response.statusText);60 }61});6263export const deleteNote = createAsyncThunk('notes/deleteNote', async (currentNote) => {64 const requestOptions = {65 method: 'DELETE',66 headers: { Authorization: `Bearer ${user.token}`, 'Content-Type': 'application/json' }67 };6869 const response = await fetch(`${process.env.REACT_APP_API_URL}/note/${currentNote._id}`, requestOptions);70 if (response.ok) {71 return currentNote;72 }73});74...