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

Tutorial Go para Web com Redis

Go para Web usando Redis

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.


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

Acesse:

localhost:8000

Por agora é só, nos vemos próxima. 😉

Código da aula: Github

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

Novamente deixo meus link de afiliados:

Hostinger

Digital Ocean

One.com

Obrigado, até a próxima e bons estudos. 😉

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>