Skip to content

Commit 22c5311

Browse files
committed
Final
1 parent 5498a99 commit 22c5311

File tree

12 files changed

+246
-10
lines changed

12 files changed

+246
-10
lines changed

README.MD

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Generar un clave rsa 1024 bits
2+
```shell openssl genrsa -out app.rsa 1024 ```
3+
Nota: -out: indica donde se va a guardar la clave privada.
4+
1024 : Es el tamaño en bits de la clave privada
5+
6+
Generar una clave publica a la clave privada
7+
8+
```shell openssl rsa -in app.rsa -pubout > app.rsa.pub ```
9+
Syntax:
10+
-in: indica la ruta de la clave privada
11+
-pubout: indica cual va ser la salida y el nombre de la clave publica generada

certificates/app.rsa

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIICXAIBAAKBgQDGdyI2sfR/np6ryjkmFKjEUc4JBQlrc5OrOdoq/6J/VyQW/VpS
3+
LNNwrjwtUP3UpP6Xk9dAynXiMmRF+jmd0bk0uitmiVVionz18kigl+b78u3VzJox
4+
ra0rC5K5UuRI7aMpzePcD3W1Igg19hBXzyPWntJXFz5yXRekFq7VuF3QrwIDAQAB
5+
AoGADbGmsLNytWOSezQG4XPHeVRTrRel4L4m0Ee7n//njHXMzbFJjCX/qOS8zjuq
6+
aAPCdV8EGTpfC+6CMLnlQ9h2uOd/a4YicuproMtBu2XWdk9TGosf2chfTmbL3I+9
7+
jYVPhrnh5gLLDLul4Fo77c1mpF8uYahGD8evIYE/GponBRECQQDuse1Ab60F83Mr
8+
R8+imjlyhdZPFXKxiDSKELI270tIaztWKI/CjQSa+RZP+i2MQbYnLs2265w7UOMg
9+
xPqrCTRzAkEA1NqP9G79r6Qpu6anFu90Y5E4FupBvw4MPTgD9iI1h36U09xdlabu
10+
3+fVtQQpDcGH9tw26XQ8DFNPmg3emqff1QJBAJBcI7UY1XgH6NuALt+UjrHop9hk
11+
jF06lyv5NQ9sYgeGcviEx41OZD6l7wynrexpwZSpBdlfXbmyDeu/tirDAmkCQFEU
12+
QCmX7cJuAgec36D47ZjPxFHWQd0I+NiI8dlcBo/qQ76//lX3FJ7trJYbU5gN1EDQ
13+
eYpL4GPBiFziU50NvVECQBRNbIk0ucX3uMky+IFQHJmkEXfhxirEXK6cyDxiky/1
14+
t/jpuki96Kz53vmq1GYiOt0kZLUv/hYzwhz0Y7wSE6Y=
15+
-----END RSA PRIVATE KEY-----

certificates/app.rsa.pub

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGdyI2sfR/np6ryjkmFKjEUc4J
3+
BQlrc5OrOdoq/6J/VyQW/VpSLNNwrjwtUP3UpP6Xk9dAynXiMmRF+jmd0bk0uitm
4+
iVVionz18kigl+b78u3VzJoxra0rC5K5UuRI7aMpzePcD3W1Igg19hBXzyPWntJX
5+
Fz5yXRekFq7VuF3QrwIDAQAB
6+
-----END PUBLIC KEY-----

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module FirstCrud
22

33
go 1.19
4+
5+
require github.com/golang-jwt/jwt/v4 v4.4.2 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
2+
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=

internal/auth/certificates.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package auth
2+
3+
import (
4+
"crypto/rsa"
5+
"github.com/golang-jwt/jwt/v4"
6+
"os"
7+
"sync"
8+
)
9+
10+
// Las dejamos privadas para que ningun paquete las pueda usar
11+
var (
12+
signKey *rsa.PrivateKey
13+
verifyKey *rsa.PublicKey
14+
once sync.Once
15+
)
16+
17+
// LoadFiles sus argumentos
18+
// son de tipo string porque le enviamos solo la ruta del archivo
19+
func LoadFiles(privateFile, publicFile string) error {
20+
var err error
21+
once.Do(func() {
22+
err = readAndLoadFiles(privateFile, publicFile)
23+
})
24+
return err
25+
}
26+
27+
func readAndLoadFiles(privateFile, publicFile string) error {
28+
29+
privateBytes, err := os.ReadFile(privateFile)
30+
if err != nil {
31+
return err
32+
}
33+
publicBytes, err := os.ReadFile(publicFile)
34+
if err != nil {
35+
return err
36+
}
37+
return parseRSA(privateBytes, publicBytes)
38+
}
39+
40+
// Function parse rsa keys
41+
42+
func parseRSA(privateBytes, publicBytes []byte) error {
43+
var err error
44+
signKey, err = jwt.ParseRSAPrivateKeyFromPEM(privateBytes)
45+
if err != nil {
46+
return err
47+
}
48+
verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(publicBytes)
49+
if err != nil {
50+
return err
51+
}
52+
return nil
53+
}

internal/auth/token.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package auth
2+
3+
import (
4+
model "FirstCrud/internal/model"
5+
"errors"
6+
"github.com/golang-jwt/jwt/v4"
7+
"time"
8+
)
9+
10+
func GenerateToken(login *model.Login) (string, error) {
11+
12+
claim := model.Claims{
13+
Email: login.Email,
14+
RegisteredClaims: jwt.RegisteredClaims{
15+
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)),
16+
Issuer: "FirstCrud",
17+
},
18+
}
19+
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claim)
20+
21+
signedToken, err := token.SignedString(signKey)
22+
if err != nil {
23+
return "", err
24+
}
25+
return signedToken, nil
26+
}
27+
28+
func ValidateToken(t string) (model.Claims, error) {
29+
token, err := jwt.ParseWithClaims(t, &model.Claims{}, verifyToken)
30+
if err != nil {
31+
return model.Claims{}, nil
32+
}
33+
34+
if !token.Valid {
35+
return model.Claims{}, errors.New("Token not valid")
36+
}
37+
38+
claim, ok := token.Claims.(*model.Claims)
39+
40+
if !ok {
41+
return model.Claims{}, errors.New("Claims no valid")
42+
}
43+
return *claim, nil
44+
}
45+
46+
func verifyToken(t *jwt.Token) (interface{}, error) {
47+
return verifyKey, nil
48+
}

internal/handler/login.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package handler
2+
3+
import (
4+
"FirstCrud/internal/auth"
5+
"FirstCrud/internal/model"
6+
"encoding/json"
7+
"net/http"
8+
)
9+
10+
type login struct {
11+
storage Storage
12+
}
13+
14+
func newLogin(s Storage) login {
15+
return login{s}
16+
}
17+
18+
func (l *login) login(w http.ResponseWriter, r *http.Request) {
19+
20+
if r.Method != http.MethodPost {
21+
response := NewResponse(
22+
"METHOD NO ALLOWED",
23+
http.StatusBadRequest, "Bad Request", nil)
24+
response.ToJSON(w)
25+
return
26+
}
27+
if r.Header.Get("Authorization") == "" {
28+
response := NewResponse("MISSING TOKEN", http.StatusBadRequest, "Bad request", nil)
29+
response.ToJSON(w)
30+
return
31+
}
32+
33+
data := model.Login{}
34+
err := json.NewDecoder(r.Body).Decode(&data)
35+
if err != nil {
36+
respose := NewResponse("JSON NO VALID", http.StatusBadRequest, "Bad Request", nil)
37+
respose.ToJSON(w)
38+
return
39+
}
40+
41+
if !isLoginValid(data) {
42+
response := NewResponse("Email or Password no valid", http.StatusBadRequest, "Bad Request", nil)
43+
response.ToJSON(w)
44+
return
45+
}
46+
token, err := auth.GenerateToken(&data)
47+
if err != nil {
48+
response := NewResponse("Error to generate token", http.StatusInternalServerError, "Internal Server Error", nil)
49+
response.ToJSON(w)
50+
return
51+
}
52+
dataToken := map[string]string{
53+
"token": token,
54+
"user": data.Email,
55+
}
56+
response := NewResponse("Login OK", http.StatusOK, nil, dataToken)
57+
response.ToJSON(w)
58+
return
59+
}
60+
61+
// Simulate a login
62+
func isLoginValid(data model.Login) bool {
63+
if data.Email == "" {
64+
return false
65+
}
66+
if data.Password == "" {
67+
return false
68+
}
69+
return data.Email == "[email protected]" && data.Password == "123456"
70+
}

internal/handler/route.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ import (
77

88
func RoutePerson(mux *http.ServeMux, storage Storage) {
99
person := newPerson(storage)
10-
mux.HandleFunc("/v1/persons", middleware.Log(person.GetAll))
10+
mux.HandleFunc("/v1/persons", middleware.Authentication(person.GetAll))
1111
mux.HandleFunc("/v1/persons/create", middleware.Authentication(person.Create))
1212
mux.HandleFunc("/v1/persons/update", middleware.Log(person.Update))
1313
mux.HandleFunc("/v1/persons/delete", middleware.Log(person.Delete))
1414
mux.HandleFunc("/v1/persons/person", middleware.Log(person.GetByID))
1515
}
16+
17+
// Route Login
18+
func RouteLogin(mux *http.ServeMux, storage Storage) {
19+
login := newLogin(storage)
20+
mux.HandleFunc("/v1/login", login.login)
21+
}

internal/middleware/middlewares.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package middleware
22

33
import (
4+
"FirstCrud/internal/auth"
45
"log"
56
"net/http"
67
"time"
@@ -23,15 +24,18 @@ func timeTrack(start time.Time, name string) {
2324
func Authentication(next http.HandlerFunc) http.HandlerFunc {
2425
return func(w http.ResponseWriter, r *http.Request) {
2526
token := r.Header.Get("Authorization")
26-
if token == "" {
27-
http.Error(w, "Forbidden", http.StatusForbidden)
28-
return
29-
}
30-
// Simulate authentication
31-
if token != "Bearer 123456789" {
27+
28+
_, err := auth.ValidateToken(token)
29+
30+
if err != nil {
3231
http.Error(w, "Forbidden", http.StatusForbidden)
3332
return
3433
}
34+
//// Simulate authentication
35+
//if token != "Bearer 123456789" {
36+
// http.Error(w, "Forbidden", http.StatusForbidden)
37+
// return
38+
//}
3539
next(w, r)
3640
}
3741
}

internal/model/login.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package model
2+
3+
import "github.com/golang-jwt/jwt/v4"
4+
5+
type Login struct {
6+
Email string `json:"email"`
7+
Password string `json:"password"`
8+
}
9+
10+
type Claims struct {
11+
Email string `json:"email"`
12+
jwt.RegisteredClaims
13+
}

main.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
package main
22

33
import (
4+
"FirstCrud/internal/auth"
45
"FirstCrud/internal/handler"
56
"FirstCrud/internal/storage"
67
"log"
78
"net/http"
89
)
910

1011
func main() {
12+
err := auth.LoadFiles("certificates/app.rsa", "certificates/app.rsa.pub")
13+
if err != nil {
14+
log.Fatal("Can't load certificates")
15+
}
16+
1117
store := storage.NewMemory()
1218
mux := http.NewServeMux()
13-
1419
//Init routes and storage
1520
handler.RoutePerson(mux, &store)
21+
// register login route
22+
handler.RouteLogin(mux, &store)
1623
log.Printf("Server running on port %s", ":8080")
17-
err := http.ListenAndServe(":8080", mux)
24+
err = http.ListenAndServe(":8080", mux)
1825
if err != nil {
1926
log.Fatal(err)
2027
}
21-
2228
// Example of how to use the middleware
2329
//execute("John", middleware.Log(middleware.Greeter))
2430
//execute("John", middleware.Log(middleware.Bye))

0 commit comments

Comments
 (0)