Aula 10 – Golang para Web – Middleware
Aula 10 – Golang para Web – Middleware
Voltar para página principal do blog
Todas as aulas desse curso
Aula 09 Aula 11
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Código da aula: Github
Melhore seu NETWORKING
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no GITHUB.
Ah, se puder, clica na estrela nos meus repositórios pra dá uma força ao meu perfil no GITHUB.
Middleware
O termo Middleware em geral é usado para agrupar tecnologias que estão entre a aplicação final e as fontes de dados.
No nosso caso, o que iremos faze é anexar uma funcionalidade aos nossos manipuladores existentes.
Vamos usar um middleware para a autenticação.
Se olharmos para o nosso código, o indexGetHandler(), ele é o único manipulador que temos até agora, que requer autenticação.
Se tivermos outros locais no código, outros endpoints, outros handlers que precisem usar autenticação, a gente teria que copiar e colar o código que lida com a autenticação, como o que já temos no indexGetHandler(), nesses vários locais.
Mas, essa repetição de código não seria bom, não é uma boa prática, então, é melhor isolar esse código em um middleware e chamar ele onde for preciso usar autenticação. 😉
A ideia é uma abordagem funcional
Precisamos criar um função que recebe como entrada um de nossos manipuladores (handlers) e retorna um novo manipulador.
Então, a primeira coisa que vamos fazer é implementar esta função middleware, a AuthRequired(), no web_app/main.go.
Ela vai retornar uma função com a mesma assinatura de indexGetHandler() que chama o método HTTP do handler que recebeu como entrada, no caso do nosso exemplo, o método HTTP do indexGetHandler().
O resultado é basicamente a execução do indexGetHandler().
É dessa forma que os middlewares funcionam, eles interceptam um outro handler, nesse caso de exemplo, handlers que precisem de autenticação.
Na AuthRequired() o que acontece é:
É verificado se tá tudo ok com as credenciais de acesso, se não tiver, o usuário é redirecionado para a página de login e o indexGetHandler() não é chamado.
Nas rotas, vamos colocar a chamada da AuthRequired() não só para o indexGetHandler() como também para o indexPostHandler(), porque não queremos que uma pessoa não logada possa ver ou postar comentários, só os usuários logados poderão ver e postar.
Com esse middleware, evitamos duplicação de código.
web_app/main.go
package main
import (
"html/template"
"net/http"
"github.com/go-redis/redis"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"golang.org/x/crypto/bcrypt"
)
//globals variables
var client *redis.Client
var store = sessions.NewCookieStore([]byte("t0p-s3cr3t"))
var templates *template.Template
func main() {
client = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
templates = template.Must(template.ParseGlob("templates/*.html"))
r := mux.NewRouter()
r.HandleFunc("/", AuthRequired(indexGetHandler)).Methods("GET")
r.HandleFunc("/", AuthRequired(indexPostHandler)).Methods("POST")
r.HandleFunc("/login", loginGetHandler).Methods("GET")
r.HandleFunc("/login", loginPostHandler).Methods("POST")
r.HandleFunc("/register", registerGetHandler).Methods("GET")
r.HandleFunc("/register", registerPostHandler).Methods("POST")
fs := http.FileServer(http.Dir("./static/"))
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
http.Handle("/", r)
http.ListenAndServe(":8001", nil)
}
func AuthRequired(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "session")
_, ok := session.Values["username"]
if !ok {
http.Redirect(w, r, "/login", 302)
return
}
handler.ServeHTTP(w, r)
}
}
//request hello handle
func indexGetHandler(w http.ResponseWriter, r *http.Request) {
comments, err := client.LRange("comments", 0, 10).Result()
if err != nil{
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
return
}
templates.ExecuteTemplate(w, "index.html", comments)
}
func indexPostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
comment := r.PostForm.Get("comment")
err := client.LPush("comments", comment).Err()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
return
}
http.Redirect(w, r, "/", 302)
}
func loginGetHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "login.html", nil)
}
func loginPostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.PostForm.Get("username")
password := r.PostForm.Get("password")
hash, err := client.Get("user: " + username).Bytes()
if err == redis.Nil {
templates.ExecuteTemplate(w, "login.html", "unknown user")
return
} else if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
return
}
err = bcrypt.CompareHashAndPassword(hash, []byte(password))
if err != nil {
templates.ExecuteTemplate(w, "login.html", "invalid login")
return
}
session, _ := store.Get(r, "session")
session.Values["username"] = username
session.Save(r, w)
http.Redirect(w, r, "/", 302)
}
func registerGetHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "register.html", nil)
}
func registerPostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.PostForm.Get("username")
password := r.PostForm.Get("password")
cost := bcrypt.DefaultCost
hash, err := bcrypt.GenerateFromPassword([]byte(password), cost)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
return
}
err = client.Set("user: "+username, hash, 0).Err()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
return
}
http.Redirect(w, r, "/login", 302)
}
//request contact page handle
func contactHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "contact.html", "This is the contact page!")
}
//request about page handle
func aboutHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "about.html", "This is the about page!")
}
Ligue o redis-server com:
redis-server
Ligue o servidor com:
go run main.go