Enriquecendo 요청 com Traefik
29000 단어 gotraefikdevopsproductivity
Authorization
nas 요청.É comum que esse token contenha informações do usuário, como por exemplo o id. Então ao receber a requisição, o backend decodifica esse token para extrair essas informações e assim relacionar com algum usuário do banco de dados. Com o usuário em mãos, executamos a ação desejada. Logo abaixou vou dar um exemplo de um serviço em Go que faz exatamente isso.
package service
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"github.com/golang-jwt/jwt"
)
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
http.HandleFunc("/", getEmail)
fmt.Println("Listening on :8081")
err := http.ListenAndServe(":8081", nil)
if err != nil {
fmt.Println(err)
}
}
func getEmail(w http.ResponseWriter, r *http.Request) {
// example from https://pkg.go.dev/github.com/golang-jwt/jwt/[email protected]
authHeader := r.Header.Get("Authorization")
tokenStr, err := getToken(authHeader)
if err != nil {
fmt.Println(err)
}
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte("my_secret_key"), nil
})
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
fmt.Println(err)
}
// get the user from the ID
// user := users.GetUserById(claims["user_id"])
userID := claims["user_id"].(string)
user := User{ID: userID, Name: "Matheus Mina", Email: "[email protected]"}
userJSON, _ := json.Marshal(user)
w.Write(userJSON)
}
func getToken(tokenStr string) (string, error) {
authHeaderParts := strings.Fields(tokenStr)
if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
return "", errors.New("Not valid")
}
return authHeaderParts[1], nil
}
Esse fluxo funciona muito bem para monolitos, mas para micro-serviços não. O problema é que ao ir para um ambiente de micro-serviços, essa logica responsável por abrir o token tem que ser replicada para cada um dos serviços novos. Se por acaso o formato do token mudar, todos os micro-serviços vão ter que se atualizar para seguir o padrão novo de token.
Para evitar esse problema, podemos fazer algo chamado de enriquecimento de requests. 요청 원본을 추가로 구성하고 백엔드에서 정보를 제공할 수 있습니다. Um serviço que faz isso, por exemplo, é o Cloudflare que adiciona alguns headers na sua requisição. Para fazer esse enriquecimento, podemos colocar uma aplicação intermediaria para fazer essa abertura de token e colocar a requisição no header das demais respostas.
Uma maneira bem simples de fazer isso é utilizar os mecanismos de middleware do Traefik . Ele é um proxy reverso e load balancer que nos permite de maneira simples fazer roteamento entre os nossos microserviços. Além disso, ele é open-source e escrito em Go. Traefik에서 미들웨어 아이디어를 활용하여 어떤 방식으로든 ficaria assim:
법적으로 괜찮습니까? Para resumir tudo, o ciclo da requisição vai funcionar assim:
Colocando a mão na massa, vamos configurar nosso serviço no Traefik receber e encaminhar as chamadas para o nosso serviço.
entryPoints:
web:
# Listen on port 8081 for incoming requests
address: :8081
providers:
# Enable the file provider to define routers / middlewares / services in file
file:
directory: /path/to/dynamic/conf
# dynamic config below
http:
routers:
# Define a connection between requests and services
user-service:
rule: "Path(`/users`)"
service: user-service
services:
# Define how to reach an existing service on our infrastructure
user-service:
loadBalancer:
servers:
- url: http://private/user-service
essa configuração, todo request para
/users
vai ir para o nosso UserService. A idéia aqui é adicionar um middleware no meio, de forma que seja transparente para o usuário que o token está sendo aberto. Para isso vamos criar um outro microserviço cuja responsabilidade seja só abrir esse token e enriquecer essa request.package middleware
import (
"errors"
"fmt"
"log"
"net/http"
"strings"
"github.com/golang-jwt/jwt"
)
func main() {
http.HandleFunc("/", setHeaderExample)
fmt.Println("Listening on :8082")
err := http.ListenAndServe(":8082", nil)
if err != nil {
log.Fatal(err)
}
}
func setHeaderExample(w http.ResponseWriter, r *http.Request) {
// example from https://pkg.go.dev/github.com/golang-jwt/jwt/[email protected]
authHeader := r.Header.Get("Authorization")
tokenStr, err := getToken(authHeader)
if err != nil {
fmt.Println(err)
}
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte("my_secret_key"), nil
})
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
fmt.Println(err)
}
// Setting the header X-User-Id"
userID := claims["user_id"].(string)
w.Header().Add("X-User-Id", userID)
w.Write([]byte("This response has the X-User-Id header"))
}
func getToken(tokenStr string) (string, error) {
authHeaderParts := strings.Fields(tokenStr)
if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
return "", errors.New("Not valid")
}
return authHeaderParts[1], nil
}
Dessa forma, traefik 미들웨어 메모 추가 필요:
http:
services:
# Define how to reach an existing service on our infrastructure
user-middleware:
loadBalancer:
servers:
- url: http://private/user-middleware
middlewares:
user-middleware:
forwardAuth:
address: "http://private/user-middleware"
authResponseHeaders:
- "X-User-ID"
UserService 유틸리티 또는 미들웨어에 대한 vamos dizer 선택:
http:
routers:
# Define a connection between requests and services
user-service:
rule: "Path(`/users`)"
service: user-service
middlewares:
- user-middleware
완전한 구성 형식:
entryPoints:
web:
# Listen on port 8081 for incoming requests
address: :8081
providers:
# Enable the file provider to define routers / middlewares / services in file
file:
directory: /path/to/dynamic/conf
# dynamic config below
http:
routers:
# Define a connection between requests and services
user-service:
rule: "Path(`/users`)"
service: user-service
middlewares:
- user-middleware
middlewares:
user-middleware:
forwardAuth:
address: "http://private/user-middleware"
authResponseHeaders:
- "X-User-ID"
services:
# Define how to reach an existing service on our infrastructure
user-service:
loadBalancer:
servers:
- url: http://private/user-service
user-middleware:
loadBalancer:
servers:
- url: http://private/user-middleware
빨리! Mágica funcionando! 현재 요청 프로 UserService vão ter o 헤더
X-User-Id
. Para finalizar, é só a gente remover o código que "abre"o token e passar a ler a informação vinda do header. Nosso 핸들러 ficaria assim:func getEmailFinal(w http.ResponseWriter, r *http.Request) {
// get the user from the ID
// user := users.GetUserById(claims["user_id"])
userID := r.Header.Get("X-User-Id")
user := User{ID: userID, Name: "Matheus Mina", Email: "[email protected]"}
userJSON, _ := json.Marshal(user)
w.Write(userJSON)
}
Ao enriquecer a request podemos simplificar o código dos nossos serviços, repassando informações utéis ao backend de forma transparente. Podemos ver que o handler do nosso serviço ficou bem mais limpo, focando somente no que ele de fato deveria fazer.
Se curtiu o post, você também pode me encontrar no , Github ou .
Reference
이 문제에 관하여(Enriquecendo 요청 com Traefik), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mfbmina/enriquecendo-requests-com-traefik-f77텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)