Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis


💻 Código de Exemplo 01 — Hashing de Senhas com Bcrypt

package security

import "golang.org/x/crypto/bcrypt"

// HashSenha usa custo 12 (2^12 iterações): equilíbrio entre segurança e
// tempo de resposta aceitável em um endpoint de cadastro/login.
func HashSenha(senha string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(senha), 12)
	return string(bytes), err
}

// ChecarSenha recalcula o hash com o salt embutido e compara em tempo
// constante, evitando timing attacks.
func ChecarSenha(senha, hash string) bool {
	return bcrypt.CompareHashAndPassword([]byte(hash), []byte(senha)) == nil
}

💻 Código de Exemplo 02 — Emissão de JWT com Claims Customizados

package security

import (
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var ChaveSecreta = []byte("troque-por-uma-chave-de-ambiente-segura")

type CustomClaims struct {
	UserID uint   `json:"user_id"`
	Email  string `json:"email"`
	jwt.RegisteredClaims
}

// GerarJWT emite um access token de curta duração (15 min), reduzindo a
// janela de exposição em caso de interceptação.
func GerarJWT(userID uint, email string) (string, error) {
	claims := CustomClaims{
		UserID: userID,
		Email:  email,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(ChaveSecreta)
}

💻 Código de Exemplo 03 — Middleware Gin de Validação de Bearer Token

package middlewares

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"

	"espec_backend_go_gin/security"
)

// ExigirJWT extrai, valida e decodifica o token antes de liberar a rota.
// Se inválido ou expirado, aborta a cadeia com 401 sem chamar o handler.
func ExigirJWT() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if !strings.HasPrefix(authHeader, "Bearer ") {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"erro": "token não fornecido"})
			return
		}
		tokenStr := strings.TrimPrefix(authHeader, "Bearer ")
		claims := &security.CustomClaims{}
		token, err := jwt.ParseWithClaims(tokenStr, claims, func(t *jwt.Token) (interface{}, error) {
			return security.ChaveSecreta, nil
		})
		if err != nil || !token.Valid {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"erro": "token inválido ou expirado"})
			return
		}
		c.Set("user_id", claims.UserID)
		c.Set("email", claims.Email)
		c.Next()
	}
}