Реализация унифицированной аутентификации и авторизации микросервисов на языке Go

Микросервисы Go

Реализация унифицированной аутентификации и авторизации микросервисов на языке Go

Дорогие читатели и друзья, с годом Крысы, желаю всем здоровья и удачи в новом году!

Недавняя эпидемия серьезна, и это особый период, каждый должен обратить внимание на защиту. Многие провинции отложили начало бизнеса, и большинство интернет-компаний также перейдут на удаленную работу на следующей неделе. Вы можете использовать несколько дней дома, чтобы научиться перезаряжаться, и вы все равно не можете выходить на улицу ( 🙂 🙂 🙂 ).

Сегодня автор будет писать о компонентной практике, связанной с микросервисами Go. Автор познакомился с языком Go несколько лет назад. В прошлом году я начал заниматься разработкой микросервисов Go. -автор книги "Go High Concurrency" Книга "Борьба с микросервисами" будет опубликована в ближайшее время. Эта статья является перехватом упреждающей версии и знакомит с реализацией единой аутентификации и авторизации микросервисов на языке Go.

1. Введение

Унифицированная проверка подлинности и авторизация являются основными функциями микросервисной архитектуры.Архитектура микросервисов отличается от архитектуры монолитных приложений тем, что аутентификация и авторизация очень централизованы. После разделения сервиса аутентификация и авторизация каждого микросервиса становятся очень децентрализованными, поэтому в архитектуре микросервиса интеграция унифицированных функций аутентификации и авторизации рассматривается как сквозная задача.

2 Общие схемы аутентификации и авторизации

Общие схемы аутентификации и авторизации включают OAuth, распределенную сессию, OpenID, JWT и т. д. Мы представим эти четыре схемы ниже.

2.1 OAuth

Введение теорий, связанных с OAuth2, в основном происходит из официальных документов OAuth2, соответствующий адресhttps://tools.ietf.org/html/rfc6749.

Цель протокола OAuth — предоставить безопасный, открытый и простой стандарт для авторизации пользовательских ресурсов. Введение на официальном сайте выглядит следующим образом:

An open protocol to allow secure API authorization in a simple and standard method from web, mobile and desktop applications.

Поскольку OAuth1 не совместим с OAuth2, логика подписи слишком сложна, а процесс авторизации слишком прост, я не буду говорить об этом здесь. Приложения.

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

Роль

В OAuth2 есть четыре основные роли.

  • владелец ресурса Владелец ресурса — это лицо, которое может предоставлять права доступа к защищенным ресурсам.Это может быть пользователь, который называется конечным пользователем.
  • сервер ресурсов Сервер ресурсов, который содержит защищенные ресурсы и позволяет запросам, содержащим маркеры доступа, получать доступ к защищенным ресурсам.
  • клиент Клиент, у которого есть авторизация владельца ресурса для доступа к защищенным ресурсам от имени владельца ресурса.
  • сервер авторизации Сервер авторизации аутентифицирует авторизацию владельца ресурса и в случае успеха отправляет токен доступа клиенту.

Во многих случаях сервер ресурсов и сервер авторизации объединяются в один, и сервер авторизации является сервером авторизации, когда выполняется взаимодействие авторизации, а сервер ресурсов является сервером ресурсов, когда запрашивается взаимодействие ресурсов. Но сервер авторизации — это отдельная сущность, которая может выдавать токены доступа, принимаемые несколькими серверами ресурсов.

Процесс согласования

Сначала посмотрите на блок-схему с официального сайта:

 +--------+                               +---------------+
 |        |--(1)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(2)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(3)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(4)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(5)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(6)--- Protected Resource ---|               |
 +--------+                               +---------------+

Это абстрактная блок-схема взаимодействия ролей OAuth2, которая в основном включает следующие 6 шагов:

  1. Клиент запрашивает авторизацию у владельца ресурса;
  2. Владелец ресурса соглашается на авторизацию и возвращает разрешение на авторизацию (Предоставление авторизации), которое представляет учетные данные авторизации владельца ресурса;
  3. Клиент несет лицензию на авторизацию, чтобы запрашивать сервер авторизации для аутентификации и запрашивает токен доступа;
  4. Сервер авторизации аутентифицирует клиента и аутентифицирует лицензию авторизации и, если она действительна, возвращает токен доступа;
  5. Клиент имеет разрешение на доступ для запроса доступа к защищенному ресурсу от сервера ресурсов;
  6. Сервер ресурсов проверяет маркер доступа и, если он действителен, принимает запрос на доступ и возвращает защищенный ресурс.Тип авторизации клиента

Чтобы получить токен доступа, клиент должен получить авторизацию от владельца ресурса. OAuth2 по умолчанию использует четыре типа авторизации и, конечно же, предоставляет механизм расширения для определения дополнительных типов авторизации. Четыре типа авторизации по умолчанию:

  • код авторизации тип кода авторизации
  • неявный упрощенный тип (также известный как неявный тип)
  • пароль владельца ресурса учетные данные пароль тип
  • учетные данные клиента тип клиента

Ниже подробно описаны часто используемые типы кодов авторизации и типы паролей.

Тип кода авторизации

Тип кода авторизации (код авторизации) позволяет владельцу ресурса напрямую взаимодействовать с сервером авторизации для авторизации через перенаправление, что позволяет избежать утечки информации о владельце ресурса клиенту.Это тип авторизации с наиболее полными функциями и наиболее строгим процесс, но требуется, чтобы клиент имел возможность взаимодействовать с прокси-сервером владельца ресурса (обычно это веб-браузер) и принимать запросы от сервера авторизации (перенаправлять на предоставление кода авторизации).Процесс авторизации выглядит следующим образом:

 +----------+
 | Resource |
 |   Owner  |
 |          |
 +----------+
      ^
      |
     (2)
 +----|-----+          Client Identifier      +---------------+
 |         -+----(1)-- & Redirection URI ---->|               |
 |  User-   |                                 | Authorization |
 |  Agent  -+----(2)-- User authenticates --->|     Server    |
 |          |                                 |               |
 |         -+----(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
  (1)  (3)                                        |      |
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(4)-- Authorization Code ---------'      |
 |  Client |          & Redirection URI                  |
 |         |                                             |
 |         |<---(5)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)
  1. Клиент направляет пользовательский агент владельца ресурса на конечную точку сервера авторизации, как правило, путем перенаправления. Информация, предоставленная клиентом, должна включать идентификатор клиента, запрошенную область, локальное состояние и URI перенаправления для возврата кода авторизации;
  2. Сервер авторизации аутентифицирует владельца ресурса (через пользовательский агент) и подтверждает, разрешает или отклоняет владелец ресурса запрос клиента на доступ;
  3. Если владелец ресурса предоставляет клиенту доступ, сервер авторизации перезванивает адрес перенаправления, предоставленный клиентом, перенаправляя пользовательский агент, и добавляет код авторизации и любое локальное состояние, ранее предоставленное клиентом, к адресу перенаправления;
  4. Клиент несет код авторизации, полученный на предыдущем шаге, для запроса маркера доступа с сервера авторизации. На этом этапе и код авторизации, и клиент аутентифицируются сервером авторизации. Клиенту необходимо указать адрес перенаправления, используемый для получения кода авторизации;
  5. Сервер авторизации аутентифицирует клиента и аутентифицирует код авторизации, гарантируя, что полученный адрес перенаправления совпадает с адресом перенаправления, использованным для получения кода авторизации на третьем этапе. Если он действителен, верните токен доступа и, возможно, токен обновления (обновить токен).

Тип пароля

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

 +----------+
 | Resource |
 |  Owner   |
 |          |
 +----------+
      v
      |    Resource Owner
     (1) Password Credentials
      |
      v
 +---------+                                  +---------------+
 |         |>--(2)---- Resource Owner ------->|               |
 |         |         Password Credentials     | Authorization |
 | Client  |                                  |     Server    |
 |         |<--(3)---- Access Token ---------<|               |
 |         |    (w/ Optional Refresh Token)   |               |
 +---------+                                  +---------------+
  1. Владелец ресурса предоставляет клиенту учетные данные, такие как его имя пользователя и пароль;
  2. Клиент несет учетные данные владельца ресурса (имя пользователя и пароль) и запрашивает токен доступа с сервера авторизации;
  3. Сервер авторизации аутентифицирует клиента и проверяет учетные данные владельца ресурса и, если они действительны, возвращает токен доступа и, возможно, токен обновления.

Обновление токена

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

2.2 Распределенная сессия

2.2.1 Что такое сеанс и что такое файл cookie?

Протокол HTTP является протоколом без сохранения состояния. После завершения обмена данными соединение между клиентом и сервером закрывается, и для повторного обмена данными необходимо установить новое соединение. Это означает, что сервер не может отслеживать сеанс из соединения.

Сеанс относится к ряду действий после входа пользователя на веб-сайт, таких как просмотр товара, добавление его в корзину и совершение покупки. Отслеживание сеанса — это метод, обычно используемый в веб-программах для отслеживания всего сеанса пользователя. Обычно используемыми технологиями отслеживания сеансов являются файлы cookie и сеансы.

Файл cookie на самом деле представляет собой небольшой фрагмент текстовой информации. Клиент запрашивает сервер, и если серверу необходимо записать статус пользователя, он использует ответ для выдачи файла cookie браузеру клиента. Клиент сохранит файл cookie.

Когда браузер снова запрашивает веб-сайт, браузер отправляет запрошенный URL-адрес на сервер вместе с файлом cookie. Сервер проверяет этот файл cookie, чтобы определить статус пользователя. Сервер также может изменить содержимое файла cookie по мере необходимости.

Сессия — еще один механизм записи состояния клиента, разница в том, что куки сохраняются в браузере клиента, а сессия сохраняется на сервере. Когда браузер клиента обращается к серверу, сервер записывает информацию о клиенте в той или иной форме.

на сервере. Это Сессия. Когда клиентский браузер снова обращается, ему нужно только найти статус клиента из сеанса.

Каждый пользователь, обращающийся к серверу, устанавливает сеанс, так как же сервер идентифицирует уникальную личность пользователя? Фактически, когда пользователь устанавливает соединение с сервером, сервер автоматически присваивает ему SessionId.

Проще говоря, Cookie определяет личность пользователя, записывая информацию на стороне клиента, а Session определяет личность пользователя, записывая информацию на стороне сервера.

2.3 OpenID

Некоторые сайты получили разрешение на вход с помощью OpenID, например, с использованием учетной записи Facebook или учетной записи Google для входа на сайт.

OpenID очень похож на OAuth. Но по сути это две совершенно разные вещи:

  • OpenID: используется только для аутентификации (аутентификации), что позволяет вам входить на несколько веб-сайтов с одной и той же учетной записью. Это просто подтверждает вашу юридическую личность.После того, как вы войдете на сайт с вашей учетной записью Facebook, сайт не имеет права доступа к вашим данным Facebook.
  • OAuth: используется для авторизации, позволяя авторизованной стороне получать доступ к пользовательским данным авторизованной стороны.

2.4 JWT

JWT, веб-токен JSON, как открытый стандарт, через компактный (компактный, быстрая передача, небольшой размер) или автономный (автономный, полезная нагрузка будет содержать всю информацию, требуемую пользователем, избегая многократного использования базы данных query) определяет безопасный объект JSON для отправки между сторонами.

Зачем вводить JWT, потому что JWT вполне может служить носителем маркера доступа и маркера обновления, представленных в предыдущем разделе, что является хорошим способом безопасной передачи информации между двумя сторонами в Интернете. Когда только сервер авторизации хранит секрет для выдачи и проверки JWT, тогда только сервер авторизации может проверить действительность JWT и отправить подписанный JWT, что только гарантирует действительность и безопасность токена с JWT в качестве носителя.

Состав JWT

Формат JWT обычно выглядит следующим образом:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiY2FuZyB3dSIsImV4cCI6MTUxODA1MTE1NywidXNlcklkIjoiMTIzNDU2In0.IV4XZ0y0nMpmMX9orv0gqsEMOxXXNQOE680CKkkPQcs

Он состоит из трех частей, каждая из которых.Отдельно они:

  • Заголовок
  • полезная нагрузка
  • Подпись

Затем подробно знакомим с каждой частью.

Header

Голова обычно состоит из двух частей:

  • тип типа, обычно jwt.
  • алгоритм шифрования alg, обычно HMAC SHA256 или RSA.

Простой пример заголовка выглядит следующим образом:

{
	"alg": "HS256"
	"typ": "JWT"
}

Затем эта часть JSON будет закодирована Base64Url, чтобы сформировать первую часть JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Playload

Полезная нагрузка — это вторая часть JWT, которая является носителем, используемым для переноса достоверной информации, в основном заявления о пользовательском объекте и дополнительных метаданных, и состоит из следующих трех частей:

  • Зарегистрированные утверждения, представляющие собой набор предопределенных, но не обязательных утверждений, которые предоставляют полезный набор утверждений, которые можно использовать вместе. В основном это iss (эмитент JWT), exp (срок действия JWT), sub (пользователь, ориентированный на JWT), aud (сторона, принимающая JWT) и т. д.
  • Общедоступные утверждения Любая информация может быть добавлена ​​к общедоступным утверждениям, как правило, информация о пользователе или информация о бизнес-расширении.
  • Частные претензии. Утверждения, определенные поставщиком JWT и потребителем, не являются ни зарегистрированными, ни публичными.

Как правило, не рекомендуется добавлять какую-либо конфиденциальную информацию в полезную нагрузку, поскольку Base64 представляет собой симметричное дешифрование, что означает, что информация в полезной нагрузке видна.

Простой пример полезной нагрузки:

{
 	"name": "cang wu",
 	"exp": 1518051157,
 	"userId": "123456"
}

Эта часть JSON будет закодирована Base64Url для формирования второй части JWT:

eyJuYW1lIjoiY2FuZyB3dSIsImV4cCI6MTUxODA1MTE1NywidXNlcklkIjoiMTIzNDU2In0

Signature

Чтобы создать подпись, вам потребуются закодированный заголовок, закодированная полезная нагрузка и секрет, и, наконец, сгенерируйте подпись, зашифровав алгоритм шифрования alg, определенный в заголовке.Псевдокод для создания подписи выглядит следующим образом:


HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Используемый алгоритм шифрованияHMACSHA256

secretОн хранится на стороне сервера для проверки JWT и выдачи JWT, поэтому он должен храниться только на стороне сервера и не должен раскрываться.

Простая подпись выглядит следующим образом:

IV4XZ0y0nMpmMX9orv0gqsEMOxXXNQOE680CKkkPQcs

Это будет третья часть JWT.

Наконец, эти три части делятся на ., чтобы сформировать окончательный JWT, следующим образом:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiY2FuZyB3dSIsImV4cCI6MTUxODA1MTE1NywidXNlcklkIjoiMTIzNDU2In0.IV4XZ0y0nMpmMX9orv0gqsEMOxXXNQOE680CKkkPQcs

3 Сервер авторизации

3.1 Общая архитектура

После приведенного выше краткого введения мы поняли общие унифицированные схемы аутентификации и аутентификации.Далее мы реализуем простую систему аутентификации и авторизации на основе протокола OAuth2 и JWT. Система в основном состоит из двух служб, сервера авторизации и сервера ресурсов, и взаимодействие между ними показано на рисунке 11-4:

Если клиент хочет получить доступ к информации о ресурсах, хранящейся у пользователя на сервере ресурсов, ему сначала необходимо передать учетные данные пользователя, чтобы запросить токен доступа с сервера авторизации. После того, как сервер авторизации проверит действительность учетных данных клиента и пользователя, он вернет сгенерированный токен доступа клиенту. Затем клиент несет токен доступа для запроса соответствующего пользовательского ресурса с сервера ресурсов, и после того, как сервер ресурсов проверит действительность токена доступа через сервер авторизации, соответствующий пользовательский ресурс будет возвращен.

Во многих случаях сервер авторизации и сервер ресурсов объединены в один, то есть могут выдавать токены доступа и иметь ограниченный доступ к пользовательским ресурсам, также могут делить свои обязанности более детально, и сервер авторизации в основном отвечает за выдача и заказ токенов.Сервер ресурсов отвечает за защиту пользовательских ресурсов, разрешая доступ к ограниченным ресурсам только запросам с действительными токенами доступа.

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

  • /oauth/token используется клиентом для передачи учетных данных пользователя для запроса токена доступа.
  • /oauth/check_token используется для проверки действительности маркера доступа и возвращает информацию о клиенте и пользователе, соответствующую маркеру доступа.

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

Сервер авторизации, который мы реализуем далее, в основном включает следующие модули, как показано на рис. 11-5:

  • ClientDetailsService, используемый для предоставления доступа к информации о клиенте;
  • UserDetailsService, используемый для получения информации о пользователе;
  • TokenGrant, используемый для выполнения различных процессов проверки в соответствии с типом авторизации, и использование TokenService для создания токенов доступа;
  • TokenService, который создает токены и управляет ими, использует TokenStore для хранения токенов;
  • TokenStore, отвечающий за хранение токенов.

Из-за нехватки места наш сервер авторизации предоставляет только типы паролей для получения токенов доступа, но предоставляет простой и расширяемый механизм, читатели могут расширять реализацию в соответствии со своими потребностями.

3.2 Пользовательские службы и клиентские службы

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

type UserDetails struct {
	// 用户标识
	UserId int
	// 用户名 唯一
	Username string
	// 用户密码
	Password string
	// 用户具有的权限
	Authorities []string
}
// 验证用户名和密码是否匹配
func (userDetails *UserDetails)IsMatch(username string, password string) bool {
	return userDetails.Password == password && userDetails.Username == username
}


type ClientDetails struct {
	// client 的标识
	ClientId string
	// client 的密钥
	ClientSecret string
	// 访问令牌有效时间,秒
	AccessTokenValiditySeconds int
	// 刷新令牌有效时间,秒
	RefreshTokenValiditySeconds int
	// 重定向地址,授权码类型中使用
	RegisteredRedirectUri string
	// 可以使用的授权类型
	AuthorizedGrantTypes []string
}

// 验证 clientId 和 ClientSecret 是否匹配
func (clientDetails *ClientDetails) IsMatch(clientId string, clientSecret string) bool {
	return clientId == clientDetails.ClientId && clientSecret == clientDetails.ClientSecret
}

В дополнение к основной информации, которую они имеют, также предоставляется метод #IsMatch для проверки соответствия информации учетной записи и пароля. Поскольку наша информация хранится в виде открытого текста, мы можем напрямую сравнить, является ли информация равной или нет.Мы также можем использовать некоторые алгоритмы шифрования в соответствии с потребностями проекта, чтобы избежать хранения конфиденциальной информации в виде открытого текста.

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

type UserDetailsService interface {
	// 根据用户名加载用户信息
	GetUserDetailByUsername(username string)(*UserDetails, error)
}

type ClientDetailService interface {
	// 根据 clientId 加载客户端信息
	GetClientDetailByClientId(clientId string) (*ClientDetails, error)
}

Информация о пользователе и информация о клиенте могут поступать из нескольких источников, мы можем загружать их из базы данных, кэша или даже из других пользовательских микросервисов через RPC.

резюме

В этой статье в основном представлены концепции, связанные с унифицированной аутентификацией и авторизацией в микросервисной архитектуре, а также структуры и сервисные интерфейсы, задействованные в реализации сервера авторизации. Генератор токенов TokenGrant, служба токенов TokenService и другие реализации будут представлены в следующей части.

Рекомендуемое чтение

Коллекция микросервисов

Подписывайтесь на свежие статьи, приглашаю обратить внимание на мой публичный номер

微信公众号