💻 Exemplos: Capítulo 10: Autenticação Stateless com JWT e Hashing de Senhas
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()
}
}