Go: RESTful - API-KEY
Afluentes: Sistemas Distribuídos e Mobile
Exemplo usando API KEY
Agora vamos ver um exemplo usando autenticação via api key.
package main
import (
"bufio"
"fmt"
"net/http"
"os"
)
func main() {
router := http.NewServeMux()
router.HandleFunc("GET /auth", func(w http.ResponseWriter, r *http.Request) {
key := r.Header.Get("X-API-KEY") // Pegamos a informação X-API-KEY do cliente
if key != getAPIKey() { // e testamos com a informação do arquivo
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
fmt.Fprintf(w, "Autentication Ok!")
})
err := http.ListenAndServe("localhost:8080", router)
if err != nil {
fmt.Println(err.Error())
}
}
// Pegamos a informação do arquivo apikey.txt que é nossa chave
// propriamente dita. Se não existir o arquivo ou der algum erro,
// retorna uma string vazia.
func getAPIKey() string {
file, err := os.Open("apikey.txt")
if err != nil {
return ""
}
defer file.Close()
scanner := bufio.NewScanner(file)
if scanner.Scan() {
return scanner.Text()
}
return ""
}
Observe que no código acima, estamos usando uma função chamada getAPIKey que busca uma informação única de um arquivo chamado apikey.txt. Caso dê algum erro, retorna uma string vazia. Então usamos essa informação para comparar com uma informação recebida da requisição, no cabeçalho, chamada X-API-KEY
. Se forem iguais, autentica, senão fecha a aplicação e retorna um código de erro. Podemos usar o curl para testar:
curl -H "X-API-KEY:01234" http://localhost:8080/auth
Veja que adicionamos um cabeçalho agora. Para validar, temos que ter o arquivo apikey.txt
com a informação 01234
dentro.
Uma maneira mais simples é colocar uma constante global e pegar a informação dessa constante. Contudo, a maneira apresentada acima permite que você possa alterar a apikey sem a necessidade de reiniciar a api.
API KEY por Usuário
Outra forma interessante é gerenciar as API KEYs por usuário, permitindo que cada usuário tenha sua própria apikey. Pode-se armazenar em um banco de dados ou arquivo json. Em banco de dados é mais recomendável, pois permite que cada usuário gerencie sua própria apikey, alterando ela quando necessário e aumentando o grau de segurança.
Então agora, nossa apikey seria um par de informações, sendo o usuário e a chave:
// Podemos ler as informações de um arquivo JSON e jogar em um MAP
apiKeys := getAPIKeys("apikeys.json")
// Pegamos as informações vindas da requisição
user := r.Header.Get("X-User")
key := r.Header.Get("X-API-KEY")
// Depois validamos
if apiKeys[user] != key {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
Nesse caso, o arquivo apikeys.json ficaria mais ou menos assim:
{
"user1": "apikey1",
"user2": "apikey2",
"user3": "apikey3"
}
E pra testar com curl:
curl -H "X-User: user1" -H "X-API-KEY: apikey1" http://localhost:8080/auth
Outra questão é que o CORS pode barrar a gente, então temos que liberar antes de chamar o ListenAndServe
c := cors.AllowAll()
r := c.Handler(router)
Outra forma é especificar o que se quer liberar:
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "X-User", "X-API-KEY"},
AllowCredentials: true,
})
handler := c.Handler(router)
Atividades
- Implemente api de acesso com autenticação de
API-KEY
por usuário com arquivoJSON
citado acima. - Implemente agora uma api de acesso de com autenticação de
API-KEY
por usuário usando uma tabela em um banco de dados com pelo menos o par deX-User
eX-API-KEY
. Veja que para testar, basta fazer uma pesquisa no banco de dados com as informações do usuário e chave e caso retorne um registro, o usuário está autorizado.