Aula 13 – Golang – Fiber – Usuário Autenticado
Aula 13 – Golang – Fiber – Usuário Autenticado
Voltar para página principal do site
Todas as aulas desse curso
Aula 12 Aula 14
Redes Sociais:
Link para a Digital Innovation
Quer aprender python3 de graça e com certificado? Acesse então:
workover
Meus link de afiliados:
Hostinger
Digital Ocean
One.com
Código da aula: Github
Melhore seu NETWORKING
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no GITHUB.
Canais do Youtube
Toti
Backing Track / Play-Along
Código Fluente
Putz!
Vocal Techniques and Exercises
PIX para doações
Aula 13 – Golang – Fiber – Usuário Autenticado
Claims
Em geral, em sistemas de autenticação e autorização, um “claim” (ou “reivindicação“, em português) é uma afirmação feita sobre um usuário autenticado ou um recurso a ser protegido.
Essa afirmação pode incluir informações como nome de usuário, papel ou função, permissões de acesso, propriedades personalizadas e assim por diante.
Em um contexto de token de acesso, como um token JWT, as reivindicações são campos que armazenam informações adicionais sobre o token e o usuário autenticado.
As reivindicações podem ser incluídas no token para fornecer informações adicionais sobre o usuário, como seu ID, nome, função ou outros detalhes relevantes.
As reivindicações são frequentemente usadas em sistemas de autorização para permitir ou negar o acesso a recursos com base nas informações fornecidas no token.
Por exemplo, um recurso pode ser protegido por uma política de acesso que permite apenas usuários com uma determinada função acessarem o recurso.
Nesse caso, a função do usuário seria incluída como uma reivindicação no token de acesso e seria usada para tomar decisões de autorização.
No contexto do JWT, as reivindicações são armazenadas como pares de chave-valor no corpo do token.
Existem três tipos de reivindicações definidas pela especificação JWT:
- Reivindicações registradas (Registered Claims): incluem informações comuns, como o emissor do token, a data de expiração, etc.
- Reivindicações públicas (Public Claims): são definidas pelo usuário e compartilhadas publicamente, mas não são obrigatórias ou registradas.
- Reivindicações privadas (Private Claims): são definidas pelo usuário e não compartilhadas publicamente.
Juntos, esses tipos de reivindicações fornecem um meio flexível e extensível para incluir informações adicionais em um token de acesso JWT.
Agora que entendemos um pouco mais sobre Claims, vamos usar no nosso código, mas, antes vamos criar o endpoint /user.
fiber-project/routes/routes.go
package routes
import (
"fiber-project/controllers"
"github.com/gofiber/fiber/v2"
)
func Setup(app *fiber.App) {
app.Post("/api/register", controllers.Register)
app.Post("/api/login", controllers.Login)
app.Get("/api/user", controllers.User)
}
fiber-project/controllers/authController.go
package controllers
import (
"fiber-project/database"
"fiber-project/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
"github.com/golang-jwt/jwt/v4"
"strconv"
"time"
)
type Claims struct {
jwt.StandardClaims
}
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["confirm_password"] {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Passwords do not match!",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirstName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
func Login(c *fiber.Ctx) error {
//get the request parameter
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
//get user by email
database.DB.Where("email = ?", data["email"]).First(&user)
//user not found
if user.Id == 0 {
c.Status(404)
return c.JSON(fiber.Map{
"message": "User not found!",
})
}
//incorrect password
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Incorrect password!",
})
}
claims := jwt.RegisteredClaims{
Issuer: strconv.Itoa(int(user.Id)),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
}
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := jwtToken.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
cookie := fiber.Cookie{
Name: "jwt",
Value: token,
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
}
c.Cookie(&cookie)
return c.JSON(fiber.Map{
"jwt": token,
})
}
func User(c *fiber.Ctx) error {
cookie := c.Cookies("jwt")
token, err := jwt.ParseWithClaims(cookie, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("secret"), nil
})
if err != nil || !token.Valid {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "unauthenticated",
})
}
return c.JSON(token)
}
Faça o login através do Postman no endopoint abaixo: http://localhost:3000/api/login
Crie uma request para o novo endpoint: http://localhost:3000/api/user
Veja que o cookie do usuário foi retornado.
fiber-project/controllers/authController.go
package controllers
import (
"fiber-project/database"
"fiber-project/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
"github.com/golang-jwt/jwt/v4"
"strconv"
"time"
)
type Claims interface {
jwt.StandardClaims
}
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["confirm_password"] {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Passwords do not match!",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirstName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
func Login(c *fiber.Ctx) error {
//get the request parameter
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
//get user by email
database.DB.Where("email = ?", data["email"]).First(&user)
//user not found
if user.Id == 0 {
c.Status(404)
return c.JSON(fiber.Map{
"message": "User not found!",
})
}
//incorrect password
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Incorrect password!",
})
}
claims := jwt.RegisteredClaims{
Issuer: strconv.Itoa(int(user.Id)),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
}
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := jwtToken.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
cookie := fiber.Cookie{
Name: "jwt",
Value: token,
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
}
c.Cookie(&cookie)
return c.JSON(fiber.Map{
"jwt": token,
})
}
func User(c *fiber.Ctx) error {
cookie := c.Cookies("jwt")
token, err := jwt.ParseWithClaims(cookie, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("secret"), nil
})
if err != nil || !token.Valid {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "unauthenticated",
})
}
claims := token.Claims.(*Claims)
id := claims.Issuer
return c.JSON(id)
}
Agora vejo o id retornado.
Vamos retornar o usuário
fiber-project/controllers/authController.go
package controllers
import (
"fiber-project/database"
"fiber-project/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
"github.com/golang-jwt/jwt/v4"
"strconv"
"time"
)
type Claims interface {
jwt.StandardClaims
}
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["confirm_password"] {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Passwords do not match!",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirstName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
func Login(c *fiber.Ctx) error {
//get the request parameter
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
//get user by email
database.DB.Where("email = ?", data["email"]).First(&user)
//user not found
if user.Id == 0 {
c.Status(404)
return c.JSON(fiber.Map{
"message": "User not found!",
})
}
//incorrect password
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Incorrect password!",
})
}
claims := jwt.RegisteredClaims{
Issuer: strconv.Itoa(int(user.Id)),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
}
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := jwtToken.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
cookie := fiber.Cookie{
Name: "jwt",
Value: token,
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
}
c.Cookie(&cookie)
return c.JSON(fiber.Map{
"jwt": token,
})
}
func User(c *fiber.Ctx) error {
cookie := c.Cookies("jwt")
token, err := jwt.ParseWithClaims(cookie, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("secret"), nil
})
if err != nil || !token.Valid {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "unauthenticated",
})
}
claims := token.Claims.(*Claims)
id := claims.Issuer
var user models.User
database.DB.Where("id = ?", id).First(&user)
return c.JSON(user)
}