Hrvatski

Sveobuhvatan vodič za implementaciju autentifikacije u Next.js aplikacijama, pokrivajući strategije, biblioteke i najbolje prakse za sigurno upravljanje korisnicima.

Next.js Autentifikacija: Potpuni Vodič za Implementaciju

Autentifikacija je kamen temeljac modernih web aplikacija. Osigurava da su korisnici oni za koje se predstavljaju, štiteći podatke i pružajući personalizirana iskustva. Next.js, sa svojim mogućnostima renderiranja na strani poslužitelja i robusnim ekosustavom, nudi moćnu platformu za izgradnju sigurnih i skalabilnih aplikacija. Ovaj vodič pruža sveobuhvatan pregled implementacije autentifikacije u Next.js-u, istražujući različite strategije i najbolje prakse.

Razumijevanje Koncepata Autentifikacije

Prije nego što zaronimo u kod, bitno je shvatiti temeljne koncepte autentifikacije:

Strategije Autentifikacije u Next.js-u

Nekoliko strategija se može primijeniti za autentifikaciju u Next.js-u, svaka sa svojim prednostima i nedostacima. Odabir pravog pristupa ovisi o specifičnim zahtjevima vaše aplikacije.

1. Autentifikacija na strani poslužitelja s Kolačićima

Ovaj tradicionalni pristup uključuje pohranjivanje informacija o sesiji na poslužitelju i korištenje kolačića za održavanje korisničkih sesija na klijentu. Kada se korisnik autentificira, poslužitelj stvara sesiju i postavlja kolačić u pregledniku korisnika. Naknadni zahtjevi od klijenta uključuju kolačić, što omogućuje poslužitelju da identificira korisnika.

Primjer Implementacije:

Iznijet ćemo osnovni primjer koristeći `bcrypt` za hashiranje lozinki i `cookies` za upravljanje sesijama. Napomena: ovo je pojednostavljeni primjer i potrebno ga je dodatno doraditi za produkcijsku upotrebu (npr. CSRF zaštita).

a) Backend (API ruta - `/pages/api/login.js`):

```javascript import bcrypt from 'bcryptjs'; import { serialize } from 'cookie'; // Placeholder baza podataka (zamijenite stvarnom bazom podataka) const users = [ { id: 1, username: 'testuser', password: bcrypt.hashSync('password123', 10) }, ]; export default async function handler(req, res) { if (req.method === 'POST') { const { username, password } = req.body; const user = users.find((u) => u.username === username); if (user && bcrypt.compareSync(password, user.password)) { const token = 'your-secret-token'; // Zamijenite robusnijom metodom generiranja tokena // Postavite kolačić res.setHeader('Set-Cookie', serialize('authToken', token, { path: '/', httpOnly: true, // Sprječava pristup kolačiću sa strane klijenta secure: process.env.NODE_ENV === 'production', // Šaljite samo preko HTTPS-a u produkciji maxAge: 60 * 60 * 24, // 1 dan })); res.status(200).json({ message: 'Prijava uspješna' }); } else { res.status(401).json({ message: 'Neispravni podaci' }); } } else { res.status(405).json({ message: 'Metoda nije dopuštena' }); } } ```

b) Frontend (Komponenta za prijavu):

```javascript import { useState } from 'react'; import { useRouter } from 'next/router'; function LoginComponent() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, password }), }); if (response.ok) { // Preusmjerite na zaštićenu stranicu router.push('/profile'); // Zamijenite svojom zaštićenom rutom } else { alert('Prijava nije uspjela'); } }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} />
); } export default LoginComponent; ```

c) Zaštićena ruta (`/pages/profile.js` - primjer):

```javascript import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; function ProfilePage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const router = useRouter(); useEffect(() => { const checkAuth = async () => { const response = await fetch('/api/checkAuth'); // Stvorite API rutu za provjeru kolačića if (response.status === 200) { setIsAuthenticated(true); } else { router.push('/login'); // Preusmjerite na stranicu za prijavu ako niste autentificirani } }; checkAuth(); }, [router]); if (!isAuthenticated) { return

Učitavanje...

; // Ili korisniku prikladnije stanje učitavanja } return (

Dobrodošli na svoj Profil!

Ovo je zaštićena stranica.

); } export default ProfilePage; ```

d) API ruta za provjeru kolačića (`/pages/api/checkAuth.js`):

```javascript import { parse } from 'cookie'; export default function handler(req, res) { const cookies = parse(req.headers.cookie || ''); const authToken = cookies.authToken; if (authToken === 'your-secret-token') { // Provjerite token res.status(200).json({ authenticated: true }); } else { res.status(401).json({ authenticated: false }); } } ```

Prednosti:

Nedostaci:

2. Besesna autentifikacija s JWT-ovima

JWT-ovi pružaju besesni mehanizam autentifikacije. Nakon što se korisnik autentificira, poslužitelj izdaje JWT koji sadrži korisničke informacije i potpisuje ga tajnim ključem. Klijent pohranjuje JWT (obično u lokalnoj pohrani ili kolačiću) i uključuje ga u zaglavlje `Authorization` naknadnih zahtjeva. Poslužitelj provjerava potpis JWT-a za autentifikaciju korisnika bez potrebe za upitom baze podataka za svaki zahtjev.

Primjer Implementacije:

Ilustrirajmo osnovnu JWT implementaciju koristeći biblioteku `jsonwebtoken`.

a) Backend (API ruta - `/pages/api/login.js`):

```javascript import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; // Placeholder baza podataka (zamijenite stvarnom bazom podataka) const users = [ { id: 1, username: 'testuser', password: bcrypt.hashSync('password123', 10) }, ]; export default async function handler(req, res) { if (req.method === 'POST') { const { username, password } = req.body; const user = users.find((u) => u.username === username); if (user && bcrypt.compareSync(password, user.password)) { const token = jwt.sign({ userId: user.id, username: user.username }, 'your-secret-key', { expiresIn: '1h' }); // Zamijenite jakim, okolišno specifičnim tajnim ključem res.status(200).json({ token }); } else { res.status(401).json({ message: 'Neispravni podaci' }); } } else { res.status(405).json({ message: 'Metoda nije dopuštena' }); } } ```

b) Frontend (Komponenta za prijavu):

```javascript import { useState } from 'react'; import { useRouter } from 'next/router'; function LoginComponent() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, password }), }); if (response.ok) { const data = await response.json(); localStorage.setItem('token', data.token); // Pohranite token u lokalnu pohranu router.push('/profile'); } else { alert('Prijava nije uspjela'); } }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} />
); } export default LoginComponent; ```

c) Zaštićena ruta (`/pages/profile.js` - primjer):

```javascript import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import jwt from 'jsonwebtoken'; function ProfilePage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const router = useRouter(); useEffect(() => { const token = localStorage.getItem('token'); if (token) { try { const decoded = jwt.verify(token, 'your-secret-key'); // Provjerite token setIsAuthenticated(true); } catch (error) { localStorage.removeItem('token'); // Uklonite nevažeći token router.push('/login'); } } else { router.push('/login'); } }, [router]); if (!isAuthenticated) { return

Učitavanje...

; } return (

Dobrodošli na svoj Profil!

Ovo je zaštićena stranica.

); } export default ProfilePage; ```

Prednosti:

Nedostaci:

3. Autentifikacija s NextAuth.js

NextAuth.js je biblioteka za autentifikaciju otvorenog koda posebno dizajnirana za Next.js aplikacije. Pojednostavljuje implementaciju autentifikacije pružanjem ugrađene podrške za različite pružatelje usluga (npr. Google, Facebook, GitHub, email/lozinka), upravljanje sesijama i sigurne API rute.

Primjer Implementacije:

Ovaj primjer pokazuje kako integrirati NextAuth.js s Google pružateljem usluga.

a) Instalirajte NextAuth.js:

npm install next-auth

b) Stvorite API rutu (`/pages/api/auth/[...nextauth].js`):

```javascript import NextAuth from 'next-auth'; import GoogleProvider from 'next-auth/providers/google'; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], secret: process.env.NEXTAUTH_SECRET, // Potrebno za sigurne sesije session: { strategy: "jwt", // Koristite JWT za sesije }, callbacks: { async jwt({ token, account }) { // Spremite OAuth access_token u token tijekom prijave if (account) { token.accessToken = account.access_token } return token }, async session({ session, token, user }) { // Pošaljite svojstva klijentu, poput access_tokena od pružatelja usluga. session.accessToken = token.accessToken return session } } }); ```

c) Ažurirajte svoj `_app.js` ili `_app.tsx` da biste koristili `SessionProvider`:

```javascript import { SessionProvider } from "next-auth/react" function MyApp({ Component, pageProps: { session, ...pageProps } }) { return ( ) } export default MyApp ```

d) Pristup korisničkoj sesiji u vašim komponentama:

```javascript import { useSession, signIn, signOut } from "next-auth/react" export default function Component() { const { data: session } = useSession() if (session) { return ( <> Signed in as {session.user.email}
) } else { return ( <> Not signed in
) } } ```

Prednosti:

Nedostaci:

4. Autentifikacija s Firebaseom

Firebase nudi sveobuhvatan skup alata za izradu web i mobilnih aplikacija, uključujući robusnu uslugu autentifikacije. Firebase Authentication podržava različite metode autentifikacije, kao što su email/lozinka, pružatelji usluga društvenih mreža (Google, Facebook, Twitter) i autentifikacija telefonskim brojem. Besprijekorno se integrira s drugim Firebase uslugama, pojednostavljujući proces razvoja.

Primjer Implementacije:

Ovaj primjer pokazuje kako implementirati autentifikaciju putem e-pošte/lozinke s Firebaseom.

a) Instalirajte Firebase:

npm install firebase

b) Inicijalizirajte Firebase u svojoj Next.js aplikaciji (npr. `firebase.js`):

```javascript import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export default app; ```

c) Stvorite komponentu za registraciju:

```javascript import { useState } from 'react'; import { createUserWithEmailAndPassword } from "firebase/auth"; import { auth } from '../firebase'; function Signup() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); try { await createUserWithEmailAndPassword(auth, email, password); alert('Registracija uspješna!'); } catch (error) { alert(error.message); } }; return (
setEmail(e.target.value)} /> setPassword(e.target.value)} />
); } export default Signup; ```

d) Stvorite komponentu za prijavu:

```javascript import { useState } from 'react'; import { signInWithEmailAndPassword } from "firebase/auth"; import { auth } from '../firebase'; import { useRouter } from 'next/router'; function Login() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e) => { e.preventDefault(); try { await signInWithEmailAndPassword(auth, email, password); router.push('/profile'); // Preusmjerite na stranicu profila } catch (error) { alert(error.message); } }; return (
setEmail(e.target.value)} /> setPassword(e.target.value)} />
); } export default Login; ```

e) Pristup korisničkim podacima i zaštita ruta: Koristite `useAuthState` hook ili `onAuthStateChanged` listener za praćenje statusa autentifikacije i zaštitu ruta.

Prednosti:

Nedostaci:

Najbolje Prakse za Sigurnu Autentifikaciju

Implementacija autentifikacije zahtijeva pažljivu pozornost sigurnosti. Evo nekoliko najboljih praksi kako biste osigurali sigurnost svoje Next.js aplikacije:

Odabir Prave Metode Autentifikacije

Najbolja metoda autentifikacije ovisi o specifičnim zahtjevima i ograničenjima vaše aplikacije. Razmotrite sljedeće čimbenike prilikom donošenja odluke:

Zaključak

Autentifikacija je kritičan aspekt modernog web razvoja. Next.js pruža fleksibilnu i moćnu platformu za implementaciju sigurne autentifikacije u vašim aplikacijama. Razumijevanjem različitih strategija autentifikacije i slijedeći najbolje prakse, možete izgraditi sigurne i skalabilne Next.js aplikacije koje štite korisničke podatke i pružaju izvrsno korisničko iskustvo. Ovaj vodič je prošao kroz neke uobičajene implementacije, ali zapamtite da je sigurnost područje koje se stalno razvija, a kontinuirano učenje je ključno. Uvijek budite u toku s najnovijim sigurnosnim prijetnjama i najboljim praksama kako biste osigurali dugoročnu sigurnost svojih Next.js aplikacija.