Шлюз микросервисов — это ключевой компонент архитектуры микросервисов. Он служит точкой входа для получения клиентских запросов и их маршрутизации в соответствующие микросервисы. Он действует как «портал» между внешними и внутренними микросервисами, координируя поток запросов и доступ к сервисам всей системы микросервисов. Функции следующие:
Шлюз микросервисов упрощает процесс взаимодействия между клиентом и серверными микросервисами, сокращает объем логики, которую необходимо обрабатывать клиенту, и предоставляет уровень промежуточного программного обеспечения, которое может лучше управлять и обслуживать всю систему микросервисов. Распространенные шлюзы микросервисов включают Nginx, Spring Cloud Gateway, Kong, INgress, Istio и т. д.
Именно потому, что шлюз микросервисного API настолько важен, он всегда был предметом споров среди военных стратегов. Традиционные ИТ-гиганты уже давно работают в этой области. Согласно отчету о жизненном цикле API, опубликованному Gartner в 2018 году, Google, CA, IBM, Red Hat и Salesforce являются ведущими поставщиками, а Kong, который более знаком разработчикам, находится в ряду провидцев.
Итак, вопрос в том, зачем нам строить новое колесо? Проще говоря, это потому, что нынешних шлюзов API микросервисов недостаточно для удовлетворения наших потребностей. Давайте сначала посмотрим на коммерческие продукты с закрытым исходным кодом. Их функции очень полны и охватывают управление полным жизненным циклом, такое как разработка API, многоязычный SDK, документация, тестирование и выпуск, а также предоставление услуг SaaS. Некоторые из них даже интегрируются с общедоступными облаками. и очень удобен в использовании. Но в то же время они приносят и две болевые точки.
Это одна из причин, почему решения шлюзов API с открытым исходным кодом стали популярными. Однако существующие продукты с открытым исходным кодом не всесильны и имеют множество недостатков.
OpenResty (открытая сетевая архитектура) — это сервер веб-приложений с открытым исходным кодом, основанный на Nginx и LuaJIT. Он сочетает в себе мощные функции языка сценариев Nginx и Lua, предоставляя разработчикам высокопроизводительный, масштабируемый и гибкий способ создания веб-приложений и микросервисов. OpenResty использует Nginx в качестве сервера и прокси, расширяя функциональность Nginx за счет внедрения механизма сценариев Lua (LuaJIT). Lua — это легкий язык сценариев с кратким синтаксисом и мощной расширяемостью, позволяющий OpenResty реализовывать более сложную логику и настраиваемые функции без изменения исходного кода Nginx. Основные особенности и преимущества:
OpenResty обычно используется для создания высокопроизводительных веб-приложений, сервисов API и шлюзов микросервисов. Он может заменить традиционные веб-серверы, обеспечивая при этом большую гибкость и возможности настройки. В крупномасштабных приложениях и средах с высоким уровнем параллелизма OpenResty продемонстрировал свои сильные преимущества и широко используется в интернет-компаниях, онлайн-играх, потоковом видео и других областях.
Теперь мы используем Openresty+Lua для реализации микросервисного API-шлюза с функциями анализа токенов и аутентификации (разбор токенов и аутентификация реализованы в Openresty, и если токен недействителен, он напрямую отклоняется). Пусть все познакомятся с процессом разработки Openresty+Lua. Блок-схема выглядит следующим образом:
Описание процесса:
package main
import (
"fmt"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
const secretKey = "Dav7kfq3iA8S!JUj8&CUkdnQe72E@Cw6" // Replace this with a strong secret key
// User struct represents a user.
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
}
var users = []User{
{1, "kubesre", "123456"},
}
func GenerateToken(user User) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id": user.ID,
"username": user.Username,
"exp": time.Now().Add(time.Hour * 2).Unix(), // Token expires in 2 hours
})
return token.SignedString([]byte(secretKey))
}
func LoginHandler(c *gin.Context) {
var input struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
return
}
for _, user := range users {
if user.Username == input.Username && user.Password == input.Password {
token, err := GenerateToken(user)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
c.JSON(http.StatusOK, gin.H{"token": token})
return
}
}
c.JSON(http.StatusUnauthorized, gin.H{"error": «Не удалось войти, пожалуйста, подтвердите свою учетную запись и пароль»})
}
func UserInfo(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Круг эксплуатации и обслуживания облачных технологий!"})
}
func main() {
r := gin.Default()
// Route to handle user login
r.POST("/login", LoginHandler)
// Routes protected by JWT authentication middleware
// You need to include the JWT token in the "Authorization" header for these routes
r.GET("/user/info", UserInfo)
fmt.Println("Server started at http://localhost:8080")
r.Run(":8080")
}
Запустить сервис
$ go mod tidy
$ go run main.go
# Установите набор инструментов управления репозиторием:
$ yum install yum-utils
# Добавить адрес склада:
$ yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
# Установите рести:
$ yum install openresty-resty
# Установите ОПМ:
$ yum install openresty-opm
# Установите компонент Jwt:
$opm get SkyLothar/lua-resty-jwt
На этом этапе lua-resty-jwt установлен и его можно использовать напрямую.
Плагин Auth-JWT:
$ cat /usr/local/openresty/lualib/resty/jwt.lua;
local auth_token = ngx.var.http_token
--Внедрение библиотеки json
local secret= "Dav7kfq3iA8S!JUj8&CUkdnQe72E@Cw6"
local cjson = require "cjson"
local jwt = require("resty.jwt")
--ngx.say(auth_token)
if auth_token == nil then
local response = {}
response["code"]=401
ответ["сообщение"]="Пароль не существует"
ngx.say(cjson.encode(response))
ngx.exit(response.code)
else
local jwt_obj = jwt:verify(secret, auth_token)
if jwt_obj.verified == false then
local response = {}
response["code"]=401
ответ["message"]="Токен недействителен"
ngx.say(cjson.encode(response))
ngx.exit(response.code)
else
ngx.exec('@user')
end
end
НастроитьOpenresty:
$ cat /usr/local/openresty/nginx/conf/nginx.conf
...
# Требуется аутентификация
location /user/info {
# Представляем расширение jwt.lua
content_by_lua_file /usr/local/openresty/lualib/resty/jwt.lua;
}
# Нет Требуется аутентификация
location /login {
proxy_pass http://192.168.40.125:8080;
}
location @user {
proxy_pass http://192.168.40.125:8080;
}
...
Перезагрузка Openresty вступает в силу:
$ /usr/local/openresty/bin/openresty -t
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
$ /usr/local/openresty/bin/openresty -s reload
Пользователь успешно входит в систему, и токен возвращается (выведите пароль учетной записи для входа и верните токен):
Если токен не передан, запросите 192.168.1.102/user/info (он вернет, что пароль не существует):
Если передан неправильный токен, запросите 192.168.1.102/user/info (будет возвращен неверный пароль):
Передайте правильный токен и запросите 192.168.1.102/user/info (обычный возвращаемый контент)
В этой статье рассказывается о API шлюза микросервиса и о том, почему нам нужно изобретать велосипед. Он также реализует небольшой пример функции синтаксического анализа и аутентификации JWT через openresty+lua, а также дает определенное представление о функции расширения openresty. Следите за практическими примерами корпоративного уровня!