Skip to content

Commit d26ca30

Browse files
committed
feat: security
- login - token - middleware
1 parent 699ec6f commit d26ca30

File tree

8 files changed

+195
-1
lines changed

8 files changed

+195
-1
lines changed

main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ import (
88
"net/http"
99
)
1010

11+
//func init() {
12+
// //chave := make([]byte, 64)
13+
// //
14+
// //if _, erro := rand.Read(chave); erro != nil {
15+
// // log.Fatal(erro)
16+
// //}
17+
// //
18+
// //stringBase64 := base64.StdEncoding.EncodeToString(chave)
19+
// //fmt.Println(stringBase64)
20+
//}
21+
1122
func main() {
1223
config.Carregar()
1324
r := router.Gerar()

src/autenticacao/token.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package autenticacao
2+
3+
import (
4+
"api/src/config"
5+
"errors"
6+
"fmt"
7+
jwt "github.com/dgrijalva/jwt-go"
8+
"net/http"
9+
"strconv"
10+
"strings"
11+
"time"
12+
)
13+
14+
func CriarToken(usuarioID uint64) (string, error) {
15+
// Permissoes que terá
16+
permissoes := jwt.MapClaims{}
17+
permissoes["authorized"] = true
18+
permissoes["exp"] = time.Now().Add(time.Hour * 6).Unix() // 6 horas
19+
permissoes["usuarioId"] = usuarioID
20+
21+
// Gera uma assinatura
22+
token := jwt.NewWithClaims(jwt.SigningMethodHS256, permissoes)
23+
return token.SignedString(config.SecretKey)
24+
}
25+
26+
func ValidarToken(r *http.Request) error {
27+
tokenString := extrairToken(r)
28+
token, erro := jwt.Parse(tokenString, retornarChaveVerificacao)
29+
if erro != nil {
30+
return erro
31+
}
32+
if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
33+
return nil
34+
}
35+
36+
return errors.New("token inválido")
37+
}
38+
39+
func ExtrairUsuarioID(r *http.Request) (uint64, error) {
40+
tokenString := extrairToken(r)
41+
token, erro := jwt.Parse(tokenString, retornarChaveVerificacao)
42+
if erro != nil {
43+
return 0, erro
44+
}
45+
46+
if permissoes, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
47+
usuarioID, erro := strconv.ParseUint(fmt.Sprintf("%.0f", permissoes["usuarioId"]), 10, 64)
48+
if erro != nil {
49+
return 0, erro
50+
}
51+
return usuarioID, nil
52+
}
53+
54+
return 0, errors.New("token inválido")
55+
}
56+
57+
func extrairToken(r *http.Request) string {
58+
token := r.Header.Get("Authorization")
59+
60+
if len(strings.Split(token, " ")) == 2 {
61+
return strings.Split(token, " ")[1]
62+
}
63+
64+
return ""
65+
}
66+
67+
func retornarChaveVerificacao(token *jwt.Token) (interface{}, error) {
68+
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
69+
return nil, fmt.Errorf("Método de assinatura inesperado! %v", token.Header["alg"])
70+
}
71+
72+
return config.SecretKey, nil
73+
}

src/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
var (
1212
StringConexaoBanco = ""
1313
Porta = 0
14+
SecretKey []byte
1415
)
1516

1617
func Carregar() {
@@ -30,4 +31,6 @@ func Carregar() {
3031
os.Getenv("DB_SENHA"),
3132
os.Getenv("DB_NOME"),
3233
)
34+
35+
SecretKey = []byte(os.Getenv("SECRET_KEY"))
3336
}

src/controllers/login.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package controllers
2+
3+
import (
4+
"api/src/autenticacao"
5+
"api/src/banco"
6+
"api/src/modelos"
7+
"api/src/repositorios"
8+
"api/src/respostas"
9+
"api/src/seguranca"
10+
"encoding/json"
11+
"fmt"
12+
"io/ioutil"
13+
"net/http"
14+
)
15+
16+
func Login(w http.ResponseWriter, r *http.Request) {
17+
corpoRequisicao, erro := ioutil.ReadAll(r.Body)
18+
if erro != nil {
19+
respostas.Erro(w, http.StatusUnprocessableEntity, erro)
20+
return
21+
}
22+
23+
var usuario modelos.Usuario
24+
if erro = json.Unmarshal(corpoRequisicao, &usuario); erro != nil {
25+
respostas.Erro(w, http.StatusBadRequest, erro)
26+
return
27+
}
28+
29+
db, erro := banco.Conectar()
30+
if erro != nil {
31+
respostas.Erro(w, http.StatusInternalServerError, erro)
32+
return
33+
}
34+
defer db.Close()
35+
36+
repositorio := repositorios.NovoRepositorioDeUsuarios(db)
37+
usuarioSalvoNoBanco, erro := repositorio.BuscarPorEmail(usuario.Email)
38+
if erro != nil {
39+
respostas.Erro(w, http.StatusInternalServerError, erro)
40+
return
41+
}
42+
if erro = seguranca.VerificarSenha(usuarioSalvoNoBanco.Senha, usuario.Senha); erro != nil {
43+
respostas.Erro(w, http.StatusUnauthorized, erro)
44+
return
45+
}
46+
47+
token, _ := autenticacao.CriarToken(usuarioSalvoNoBanco.ID)
48+
fmt.Println(token)
49+
w.Write([]byte(token))
50+
}

src/middlewares/middlewares.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package middlewares
2+
3+
import (
4+
"api/src/autenticacao"
5+
"api/src/respostas"
6+
"log"
7+
"net/http"
8+
)
9+
10+
func Logger(next http.HandlerFunc) http.HandlerFunc {
11+
return func(w http.ResponseWriter, r *http.Request) {
12+
log.Printf("\n %s %s %s", r.Method, r.RequestURI, r.Host)
13+
next(w, r)
14+
}
15+
}
16+
17+
func Autenticar(next http.HandlerFunc) http.HandlerFunc {
18+
return func(w http.ResponseWriter, r *http.Request) {
19+
if erro := autenticacao.ValidarToken(r); erro != nil {
20+
respostas.Erro(w, http.StatusUnauthorized, erro)
21+
return
22+
}
23+
next(w, r)
24+
}
25+
}

src/router/rotas/login.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package rotas
2+
3+
import (
4+
"api/src/controllers"
5+
"net/http"
6+
)
7+
8+
var rotaLogin = Rota{
9+
URI: "/login",
10+
Metodo: http.MethodPost,
11+
Funcao: controllers.Login,
12+
RequerAutenticacao: false,
13+
}

src/router/rotas/rotas.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rotas
22

33
import (
4+
"api/src/middlewares"
45
"github.com/gorilla/mux"
56
"net/http"
67
)
@@ -16,9 +17,16 @@ type Rota struct {
1617
// Configurar coloca todas as rotas dentro do router
1718
func Configurar(r *mux.Router) *mux.Router {
1819
rotas := rotasUsuarios
20+
rotas = append(rotas, rotaLogin)
1921

2022
for _, rota := range rotas {
21-
r.HandleFunc(rota.URI, rota.Funcao).Methods(rota.Metodo)
23+
if rota.RequerAutenticacao {
24+
r.HandleFunc(rota.URI,
25+
middlewares.Logger(middlewares.Autenticar(rota.Funcao)),
26+
).Methods(rota.Metodo)
27+
} else {
28+
r.HandleFunc(rota.URI, middlewares.Logger(rota.Funcao)).Methods(rota.Metodo)
29+
}
2230
}
2331

2432
return r

src/seguranca/seguranca.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package seguranca
2+
3+
import "golang.org/x/crypto/bcrypt"
4+
5+
func Hash(senha string) ([]byte, error) {
6+
return bcrypt.GenerateFromPassword([]byte(senha), bcrypt.DefaultCost)
7+
}
8+
9+
func VerificarSenha(senhaHash, senhaString string) error {
10+
return bcrypt.CompareHashAndPassword([]byte(senhaHash), []byte(senhaString))
11+
}

0 commit comments

Comments
 (0)