Skip to content

Commit

Permalink
feat: security
Browse files Browse the repository at this point in the history
- login
- token
- middleware
  • Loading branch information
dexfs committed Sep 18, 2023
1 parent 699ec6f commit d26ca30
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 1 deletion.
11 changes: 11 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import (
"net/http"
)

//func init() {
// //chave := make([]byte, 64)
// //
// //if _, erro := rand.Read(chave); erro != nil {
// // log.Fatal(erro)
// //}
// //
// //stringBase64 := base64.StdEncoding.EncodeToString(chave)
// //fmt.Println(stringBase64)
//}

func main() {
config.Carregar()
r := router.Gerar()
Expand Down
73 changes: 73 additions & 0 deletions src/autenticacao/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package autenticacao

import (
"api/src/config"
"errors"
"fmt"
jwt "github.com/dgrijalva/jwt-go"
"net/http"
"strconv"
"strings"
"time"
)

func CriarToken(usuarioID uint64) (string, error) {
// Permissoes que terá
permissoes := jwt.MapClaims{}
permissoes["authorized"] = true
permissoes["exp"] = time.Now().Add(time.Hour * 6).Unix() // 6 horas
permissoes["usuarioId"] = usuarioID

// Gera uma assinatura
token := jwt.NewWithClaims(jwt.SigningMethodHS256, permissoes)
return token.SignedString(config.SecretKey)
}

func ValidarToken(r *http.Request) error {
tokenString := extrairToken(r)
token, erro := jwt.Parse(tokenString, retornarChaveVerificacao)
if erro != nil {
return erro
}
if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return nil
}

return errors.New("token inválido")
}

func ExtrairUsuarioID(r *http.Request) (uint64, error) {
tokenString := extrairToken(r)
token, erro := jwt.Parse(tokenString, retornarChaveVerificacao)
if erro != nil {
return 0, erro
}

if permissoes, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
usuarioID, erro := strconv.ParseUint(fmt.Sprintf("%.0f", permissoes["usuarioId"]), 10, 64)
if erro != nil {
return 0, erro
}
return usuarioID, nil
}

return 0, errors.New("token inválido")
}

func extrairToken(r *http.Request) string {
token := r.Header.Get("Authorization")

if len(strings.Split(token, " ")) == 2 {
return strings.Split(token, " ")[1]
}

return ""
}

func retornarChaveVerificacao(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Método de assinatura inesperado! %v", token.Header["alg"])
}

return config.SecretKey, nil
}
3 changes: 3 additions & 0 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
var (
StringConexaoBanco = ""
Porta = 0
SecretKey []byte
)

func Carregar() {
Expand All @@ -30,4 +31,6 @@ func Carregar() {
os.Getenv("DB_SENHA"),
os.Getenv("DB_NOME"),
)

SecretKey = []byte(os.Getenv("SECRET_KEY"))
}
50 changes: 50 additions & 0 deletions src/controllers/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package controllers

import (
"api/src/autenticacao"
"api/src/banco"
"api/src/modelos"
"api/src/repositorios"
"api/src/respostas"
"api/src/seguranca"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

func Login(w http.ResponseWriter, r *http.Request) {
corpoRequisicao, erro := ioutil.ReadAll(r.Body)
if erro != nil {
respostas.Erro(w, http.StatusUnprocessableEntity, erro)
return
}

var usuario modelos.Usuario
if erro = json.Unmarshal(corpoRequisicao, &usuario); erro != nil {
respostas.Erro(w, http.StatusBadRequest, erro)
return
}

db, erro := banco.Conectar()
if erro != nil {
respostas.Erro(w, http.StatusInternalServerError, erro)
return
}
defer db.Close()

repositorio := repositorios.NovoRepositorioDeUsuarios(db)
usuarioSalvoNoBanco, erro := repositorio.BuscarPorEmail(usuario.Email)
if erro != nil {
respostas.Erro(w, http.StatusInternalServerError, erro)
return
}
if erro = seguranca.VerificarSenha(usuarioSalvoNoBanco.Senha, usuario.Senha); erro != nil {
respostas.Erro(w, http.StatusUnauthorized, erro)
return
}

token, _ := autenticacao.CriarToken(usuarioSalvoNoBanco.ID)
fmt.Println(token)
w.Write([]byte(token))
}
25 changes: 25 additions & 0 deletions src/middlewares/middlewares.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package middlewares

import (
"api/src/autenticacao"
"api/src/respostas"
"log"
"net/http"
)

func Logger(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("\n %s %s %s", r.Method, r.RequestURI, r.Host)
next(w, r)
}
}

func Autenticar(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if erro := autenticacao.ValidarToken(r); erro != nil {
respostas.Erro(w, http.StatusUnauthorized, erro)
return
}
next(w, r)
}
}
13 changes: 13 additions & 0 deletions src/router/rotas/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package rotas

import (
"api/src/controllers"
"net/http"
)

var rotaLogin = Rota{
URI: "/login",
Metodo: http.MethodPost,
Funcao: controllers.Login,
RequerAutenticacao: false,
}
10 changes: 9 additions & 1 deletion src/router/rotas/rotas.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rotas

import (
"api/src/middlewares"
"github.com/gorilla/mux"
"net/http"
)
Expand All @@ -16,9 +17,16 @@ type Rota struct {
// Configurar coloca todas as rotas dentro do router
func Configurar(r *mux.Router) *mux.Router {
rotas := rotasUsuarios
rotas = append(rotas, rotaLogin)

for _, rota := range rotas {
r.HandleFunc(rota.URI, rota.Funcao).Methods(rota.Metodo)
if rota.RequerAutenticacao {
r.HandleFunc(rota.URI,
middlewares.Logger(middlewares.Autenticar(rota.Funcao)),
).Methods(rota.Metodo)
} else {
r.HandleFunc(rota.URI, middlewares.Logger(rota.Funcao)).Methods(rota.Metodo)
}
}

return r
Expand Down
11 changes: 11 additions & 0 deletions src/seguranca/seguranca.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package seguranca

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

func Hash(senha string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(senha), bcrypt.DefaultCost)
}

func VerificarSenha(senhaHash, senhaString string) error {
return bcrypt.CompareHashAndPassword([]byte(senhaHash), []byte(senhaString))
}

0 comments on commit d26ca30

Please sign in to comment.