микросервисы go-kit: аутентификация JWT

Микросервисы
микросервисы go-kit: аутентификация JWT

Чтобы обеспечить безопасность и стабильность системы и защитить безопасность пользовательских данных, в службу обычно вводятся методы аутентификации личности для безопасного перехвата, проверки и фильтрации запросов пользователей. Обычно используемые методы аутентификации:

  • JWT: JWT предоставляет метод выдачи токена доступа (токена доступа) и проверки выданного подписанного токена доступа. Сам токен содержит ряд утверждений, согласно которым приложение может ограничить доступ пользователя к ресурсу.
  • OAuth2: OAuth2 — это структура авторизации, которая предоставляет подробный набор механизмов авторизации (руководство). Пользователи или приложения могут разрешать сторонним приложениям доступ к определенным ресурсам с помощью общедоступных или частных настроек.
  • Базовая: аутентификация по имени пользователя и паролю, которая выполняется с каждым запросом, что не является безопасным.

Практическая тренировка

В этой статье будет представлен механизм проверки jwt в микросервисе go-kit для реализации выпуска и проверки токена. Принцип jwt больше не разрабатывается, и вы можете обратиться к последней ссылке. Кратко опишу идею реализации:

  • Создайте новый интерфейс входа и проверьте имя пользователя и пароль. Проверка возвращается клиенту путем создания токена.
  • Добавьте механизм проверки токена в интерфейс расчета, который инкапсулируется промежуточным программным обеспечением, предоставляемым go-kit.
  • В этом примере используется реализация go стороннего jwt.dgrijalva/jwt-go

Шаг 1: Подготовка кода

Скопируйте каталог arithmetic_circuitbreaker_demo, переименуйте его в arithmetic_jwt_demo и переименуйте каталог регистров в service.

Установите зависимую стороннюю библиотеку jwt:

go get github.com/dgrijalva/jwt-go

Шаг 2: Создайте jwt.go

существуетserviceСоздайте файл в каталогеjwt.go.

  • Сначала определите ключ, необходимый для генерации токена (это самое важное в jwt, и его нельзя упускать).
  • 自定义声明。 существуетStandardClaimsДобавленUserId,NameДва поля, другие поля, такие как роли, могут быть расширены в соответствии с фактическими потребностями.
  • определениеkeyfunc, этот метод используется как callback-функция при проверке токена, что будет описано позже.
  • Определить метод для создания токенаSign. Здесь для генерации напрямую вызывается сторонняя библиотека jwt, а время истечения токена установлено на 2 минуты для удобства демонстрации.

следующееjwt.goВесь код:

//secret key
var secretKey = []byte("abcd1234!@#$")

// ArithmeticCustomClaims 自定义声明
type ArithmeticCustomClaims struct {
	UserId string `json:"userId"`
	Name   string `json:"name"`

	jwt.StandardClaims
}

// jwtKeyFunc 返回密钥
func jwtKeyFunc(token *jwt.Token) (interface{}, error) {
	return secretKey, nil
}

// Sign 生成token
func Sign(name, uid string) (string, error) {

	//为了演示方便,设置两分钟后过期
	expAt := time.Now().Add(time.Duration(2) * time.Minute).Unix()

	// 创建声明
	claims := ArithmeticCustomClaims{
		UserId: uid,
		Name:   name,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expAt,
			Issuer:    "system",
		},
	}

	//创建token,指定加密算法为HS256
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	//生成token
	return token.SignedString(secretKey)
}

Шаг 3. Добавьте интерфейс входа в систему.

Сервисный уровень: добавьте новый интерфейс входа в систему в соответствии с архитектурой go-kit, чтобы:

  • Добавлен метод входа в интерфейс службы.
  • Реализуйте метод Login в ArithmeticService: проверьте имя пользователя и пароль и вызовите метод Sign jwt для создания маркера;
  • Реализовать метод Login в loggingMiddleware;
  • Реализовать метод Login в metricMiddleware;
// Service Define a service interface
type Service interface {
        //……

	// HealthCheck
	Login(name, pwd string) (string, error)
}

func (s ArithmeticService) Login(name, pwd string) (string, error) {
	if name == "name" && pwd == "pwd" {
		token, err := Sign(name, pwd)
		return token, err
	}

	return "", errors.New("Your name or password dismatch")
}

Уровень конечной точки: новый запрашивает интерфейс входа в систему и требуемую структуру объекта ответа, метод подготовки, созданный конечной точкой.

// AuthRequest
type AuthRequest struct {
	Name string `json:"name"`
	Pwd  string `json:"pwd"`
}

// AuthResponse
type AuthResponse struct {
	Success bool   `json:"success"`
	Token   string `json:"token"`
	Error   string `json:"error"`
}

func MakeAuthEndpoint(svc Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		req := request.(AuthRequest)

		token, err := svc.Login(req.Name, req.Pwd)

		var resp AuthResponse
		if err != nil {
			resp = AuthResponse{
				Success: err == nil,
				Token:   token,
				Error:   err.Error(),
			}
		} else {
			resp = AuthResponse{
				Success: err == nil,
				Token:   token,
			}
		}

		return resp, nil
	}
}

Транспортный уровень: напишите методы декодирования и кодирования и добавьте маршрутизацию интерфейса входа в систему. При этом в интерфейс calculate добавлена ​​логика обнаружения токена: перед обработкой запроса из заголовка HTTP-запроса считывается аутентификационная информация, и в случае успешного чтения добавляется контекст запроса. Здесь непосредственно используется метод HTTPToContext, предоставляемый go-kit.

func decodeLoginRequest(_ context.Context, r *http.Request) (interface{}, error) {
	var loginRequest AuthRequest
	if err := json.NewDecoder(r.Body).Decode(&loginRequest); err != nil {
		return nil, err
	}
	return loginRequest, nil
}

func encodeLoginResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	return json.NewEncoder(w).Encode(response)
}

Добавьте http-маршрут:

r.Methods("POST").Path("/calculate/{type}/{a}/{b}").Handler(kithttp.NewServer(
	endpoints.ArithmeticEndpoint,
	decodeArithmeticRequest,
	encodeArithmeticResponse,
    //增加了options
	append(options, kithttp.ServerBefore(kitjwt.HTTPToContext()))...,
))

// ...

r.Methods("POST").Path("/login").Handler(kithttp.NewServer(
	endpoints.AuthEndpoint,
	decodeLoginRequest,
	encodeLoginResponse,
	options...,
))

Шаг 4: Изменить main.go

Разверните исходные ArithmeticEndpoints, добавьте AuthEndpoint, добавьте код логики создания AuthEndpoint и добавьте упаковку, такую ​​как текущее ограничение и отслеживание ссылок.

//身份认证Endpoint
authEndpoint := MakeAuthEndpoint(svc)
authEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(authEndpoint)
authEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "login-endpoint")(authEndpoint)

//把算术运算Endpoint\健康检查、登录Endpoint封装至ArithmeticEndpoints
endpts := ArithmeticEndpoints{
	ArithmeticEndpoint:  calEndpoint,
	HealthCheckEndpoint: healthEndpoint,
	AuthEndpoint:        authEndpoint,
}

Поскольку мы требуем, чтобы доступ к интерфейсу расчета был возможен только тогда, когда токен действителен, добавьте код проверки токена в calEndpoint (последняя строка кода, напрямую используйте промежуточное программное обеспечение, предоставленное go-kit):

calEndpoint := MakeArithmeticEndpoint(svc)
calEndpoint = NewTokenBucketLimitterWithBuildIn(ratebucket)(calEndpoint)
calEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "calculate-endpoint")(calEndpoint)
calEndpoint = kitjwt.NewParser(jwtKeyFunc, jwt.SigningMethodHS256, kitjwt.StandardClaimsFactory)(calEndpoint)

Шаг 5: Запустите и протестируйте

пройти черезdocker-composeЗапустите консул, зипкин, hystrix-dashboard, затем запустите Gateyway, наконец, запустите сервис (указав консул и адреса сервисов).

Установите запрос POST http://localhost:9090/arithmetic/login в Postman, а тело будет следующим:

{
    "name": "name",
    "pwd": "pwd"
}

Можно увидеть следующие результаты:

Затем запросите интерфейс расчета и установите авторизацию в заголовке, результат будет следующим:

Через две минуты проверьте еще раз, вы обнаружите, что срок действия возвращенного токена истек.

Суммировать

В этой статье собраны примеры внедрения jwt в микросервисы go-kit. Добавлен интерфейс входа в систему, так что интерфейс расчета может работать только тогда, когда токен действителен. Благодаря характеристикам аутентификации jwt действительность токена, запрошенного пользователем после успешного входа в систему, больше не зависит от центра аутентификации.По сравнению с OAuth2 это может значительно снизить нагрузку на центр аутентификации, упрощая горизонтальное расширение микросервисов. .

использованная литература

Эта статья была впервые опубликована в моей публичной учетной записи WeChat [Xi Yiang Bar], пожалуйста, отсканируйте код, чтобы следовать!