Skip to content

Commit 11e95d7

Browse files
committed
feat: implement registration, login, token validation and user role redirection
1 parent dc01e0b commit 11e95d7

File tree

6 files changed

+151
-33
lines changed

6 files changed

+151
-33
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/api/login/route.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
3+
const AUTH_API = 'http://auth:8080'
4+
5+
export async function POST(req: NextRequest) {
6+
try {
7+
const body = await req.json()
8+
const backendRes = await fetch(`${AUTH_API}/auth/login`, {
9+
method: 'POST',
10+
headers: { 'Content-Type': 'application/json' },
11+
body: JSON.stringify(body),
12+
})
13+
const data = await backendRes.json()
14+
return new NextResponse(JSON.stringify(data), {
15+
status: backendRes.status,
16+
headers: { 'Content-Type': 'application/json' },
17+
})
18+
} catch {
19+
return new NextResponse(JSON.stringify({ detail: 'Erro interno no proxy.' }), {
20+
status: 500,
21+
headers: { 'Content-Type': 'application/json' },
22+
})
23+
}
24+
}

src/app/api/register/route.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
3+
const AUTH_API = 'http://auth:8080'
4+
5+
export async function POST(req: NextRequest) {
6+
try {
7+
const body = await req.json()
8+
const backendRes = await fetch(`${AUTH_API}/users/`, {
9+
method: 'POST',
10+
headers: { 'Content-Type': 'application/json' },
11+
body: JSON.stringify(body),
12+
})
13+
const data = await backendRes.json()
14+
return new NextResponse(JSON.stringify(data), {
15+
status: backendRes.status,
16+
headers: { 'Content-Type': 'application/json' },
17+
})
18+
} catch {
19+
return new NextResponse(JSON.stringify({ detail: 'Erro interno no proxy.' }), {
20+
status: 500,
21+
headers: { 'Content-Type': 'application/json' },
22+
})
23+
}
24+
}

src/app/api/userinfo/route.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
3+
const AUTH_API = 'http://auth:8080'
4+
5+
type User = {
6+
id: number
7+
username: string
8+
email: string
9+
role: 'PLAYER' | 'DUNGEON_MASTER'
10+
}
11+
12+
export async function GET(req: NextRequest) {
13+
const auth = req.headers.get('authorization')
14+
if (!auth?.startsWith('Bearer ')) {
15+
return NextResponse.json({ message: 'Token não fornecido' }, { status: 401 })
16+
}
17+
18+
const token = auth.replace('Bearer ', '')
19+
let username: string | null = null
20+
21+
try {
22+
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString('utf-8'))
23+
username = payload?.sub
24+
} catch {
25+
return NextResponse.json({ message: 'Token inválido' }, { status: 401 })
26+
}
27+
28+
if (!username) {
29+
return NextResponse.json({ message: 'Username não encontrado no token' }, { status: 401 })
30+
}
31+
32+
const listRes = await fetch(`${AUTH_API}/users`, {
33+
headers: { Authorization: `Bearer ${token}` },
34+
})
35+
36+
if (!listRes.ok) {
37+
return NextResponse.json({ message: 'Erro ao buscar usuários' }, { status: listRes.status })
38+
}
39+
40+
const listData = await listRes.json()
41+
42+
const users: User[] = listData.users
43+
const user = users.find((u) => u.username === username)
44+
45+
if (!user) {
46+
return NextResponse.json({ message: 'Usuário não encontrado' }, { status: 404 })
47+
}
48+
49+
const userRes = await fetch(`${AUTH_API}/users/${user.id}`, {
50+
headers: { Authorization: `Bearer ${token}` },
51+
})
52+
53+
if (!userRes.ok) {
54+
return NextResponse.json({ message: 'Erro ao buscar dados do usuário' }, { status: userRes.status })
55+
}
56+
57+
const userData = await userRes.json()
58+
59+
return NextResponse.json({ role: userData.role }, { status: 200 })
60+
}

src/app/login/page.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
'use client'
2-
32
import { useState } from 'react'
3+
import { useRouter } from 'next/navigation'
44
import Image from 'next/image'
55
import Link from 'next/link'
6-
import { useRouter } from 'next/navigation'
76
import styles from './login.module.css'
87

98
export default function LoginPage() {
@@ -14,34 +13,49 @@ export default function LoginPage() {
1413

1514
const handleSubmit = async (e: React.FormEvent) => {
1615
e.preventDefault()
16+
setMensagem('')
1717

1818
try {
19-
const res = await fetch('http://localhost:8080/auth/login', {
19+
const loginRes = await fetch('/api/login', {
2020
method: 'POST',
2121
headers: { 'Content-Type': 'application/json' },
2222
body: JSON.stringify({ username, password: senha }),
2323
})
2424

25-
const data = await res.json()
25+
const loginData = await loginRes.json()
26+
27+
if (!loginRes.ok) {
28+
setMensagem(loginData.detail || 'Erro no login.')
29+
return
30+
}
31+
32+
const token = loginData.access_token
2633

27-
if (res.ok && data.access_token) {
28-
localStorage.setItem('token', data.access_token)
34+
localStorage.setItem('token', token)
35+
36+
const userRes = await fetch('/api/userinfo', {
37+
method: 'GET',
38+
headers: { Authorization: `Bearer ${token}` },
39+
})
40+
41+
const userInfo = await userRes.json()
42+
43+
if (!userRes.ok || !userInfo.role) {
44+
setMensagem('Não foi possível recuperar o role do usuário.')
45+
return
46+
}
2947

30-
setMensagem('Login bem-sucedido!')
31-
const role = localStorage.getItem('role')
48+
const role = userInfo.role.toUpperCase()
3249

33-
if (role === 'DUNGEON_MASTER') {
34-
router.push('/dashboard-master')
35-
} else if (role === 'PLAYER') {
36-
router.push('/dashboard-player')
37-
} else {
38-
setMensagem('Função de usuário não encontrada. Faça o cadastro novamente.')
39-
}
50+
if (role === 'DUNGEON_MASTER') {
51+
router.push('/dashboard-master')
52+
} else if (role === 'PLAYER') {
53+
router.push('/dashboard-player')
4054
} else {
41-
setMensagem(data.error || data.detail || 'Erro no login.')
55+
setMensagem('Função do usuário desconhecida.')
4256
}
4357
} catch {
44-
setMensagem('Erro de conexão com o servidor.')
58+
setMensagem('Erro ao conectar com o servidor.')
4559
}
4660
}
4761

src/app/register/page.tsx

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,29 @@ export default function RegisterPage() {
3232
const roleToSend = role === 'DUNGEON_MASTER' ? 'dungeon master' : 'player'
3333

3434
try {
35-
const response = await fetch('http://localhost:8080/users/', {
35+
const response = await fetch('/api/register', {
3636
method: 'POST',
3737
headers: { 'Content-Type': 'application/json' },
38-
body: JSON.stringify({
39-
email,
40-
password,
41-
username,
42-
role: roleToSend,
43-
}),
38+
body: JSON.stringify({ email, password, username, role: roleToSend }),
4439
})
4540

41+
const result = await response.json()
42+
4643
if (!response.ok) {
47-
const errorData = await response.json()
48-
if (Array.isArray(errorData.detail)) {
49-
const messages = (errorData.detail as { msg: string }[]).map((e) => e.msg).join('; ')
44+
if (Array.isArray(result.detail)) {
45+
const messages = result.detail.map((e: { msg: string }) => e.msg).join('; ')
5046
setError(messages)
5147
} else {
52-
setError(errorData.detail || 'Erro ao cadastrar usuário.')
48+
setError(result.detail || 'Erro ao cadastrar usuário.')
5349
}
5450
} else {
55-
localStorage.setItem('role', role)
5651
router.push('/login')
5752
}
5853
} catch (err) {
59-
let errorMessage = 'Ocorreu um erro desconhecido ao tentar conectar com o servidor.'
60-
if (err instanceof Error) errorMessage = `Erro: ${err.message}`
61-
else if (typeof err === 'string') errorMessage = `Erro: ${err}`
54+
const errorMessage =
55+
err instanceof Error
56+
? `Erro: ${err.message}`
57+
: 'Ocorreu um erro desconhecido ao tentar conectar com o servidor.'
6258
setError(errorMessage)
6359
} finally {
6460
setLoading(false)

0 commit comments

Comments
 (0)