Введение
В этом руководстве показано, как создать кнопку "Вход с помощью GitHub" для веб-сайта. Веб-сайт будет использовать GitHub App для создания маркера доступа пользователя через поток веб-приложения. Затем веб-сайт использует маркер доступа пользователя для выполнения запросов API от имени пользователя, прошедшего проверку подлинности.
В этом руководстве используется Ruby, но вы можете использовать поток веб-приложения с любым языком программирования, используемым для веб-разработки.
Сведения о потоке веб-приложения и маркерах доступа пользователей
Приложение должно использовать маркер доступа пользователя, если вы хотите приказать действия приложения пользователю. Дополнительные сведения см. в разделе Проверка подлинности с помощью Приложение GitHub от имени пользователя.
Существует два способа создания маркера доступа пользователя для GitHub App: поток веб-приложения и поток устройства. Если приложение имеет доступ к веб-интерфейсу, следует использовать поток веб-приложения. Если приложение не имеет доступа к веб-интерфейсу, следует использовать поток устройства. Дополнительные сведения см. в разделах Создание маркера доступа пользователя для Приложение GitHub и Создание интерфейса командной строки с помощью Приложение GitHub.
Предварительные требования
В этом руководстве предполагается, что вы уже создали GitHub App. Дополнительные сведения о создании приложения см. в разделе Создание приложения GitHub.
Перед выполнением этого руководства необходимо задать URL-адрес обратного вызова для приложения. В этом руководстве используется локальный сервер Sinatra с URL-адресом http://localhost:4567
по умолчанию . Например, для работы с URL-адресом по умолчанию для локального приложения Sinatra url-адресом обратного вызова может быть http://localhost:4567/github/callback
. Когда вы будете готовы к развертыванию приложения, вы можете изменить URL-адрес обратного вызова, чтобы использовать адрес активного сервера. Дополнительные сведения об обновлении URL-адреса обратного вызова для приложения см. в разделах Изменение приложения GitHub и Сведения о URL-адресе обратного вызова авторизации пользователя.
В этом руководстве предполагается, что у вас есть базовое представление о Ruby и системе шаблонов Ruby ( ERB). Дополнительные сведения см. в разделе Ruby и ERB.
Установка зависимостей
В этом руководстве для создания веб-приложения с помощью Ruby используется драгоценный камень Ruby Sinatra. Дополнительные сведения см. в файле сведений О Sinatra.
В этом руководстве для доступа к значениям, хранящимся в файле, используется драгоценный .env
камень Ruby dotenv. Дополнительные сведения см. в файле сведений dotenv.
Чтобы выполнить инструкции из этого руководства, необходимо установить драгоценные камни Sinatra и dotenv в проекте Ruby. Например, это можно сделать с помощью bundler:
-
Если у вас еще не установлено средство bundler, выполните в терминале следующую команду:
gem install bundler
-
Если у вас еще нет файла Gemfile для приложения, выполните в терминале следующую команду:
bundle init
-
Если у вас еще нет gemfile.lock для приложения, выполните в терминале следующую команду:
bundle install
-
Установите gems, выполнив следующие команды в терминале:
bundle add sinatra
bundle add dotenv
Хранение идентификатора и секрета клиента
В этом руководстве показано, как сохранить идентификатор клиента и секрет клиента в переменных среды и получить к ним доступ с помощью ENV.fetch
. При развертывании приложения необходимо изменить способ хранения идентификатора и секрета клиента. Дополнительные сведения см. в разделе Безопасное хранение секрета клиента.
-
Перейдите к настройкам учетной записи.
-
Для приложения GitHub App, принадлежащего учетной записи пользователя, нажмите на фото своего профиля в правом верхнем углу любой страницы и выберите Настройки.
-
Для приложения GitHub App, принадлежащего организации, нажмите на фото своего профиля в правом верхнем углу любой страницы и выберите Ваши организации. Затем нажмите Настройки справа от организации.
-
-
На левой боковой панели щелкните Параметры разработчика.
-
На левой боковой панели щелкните GitHub Apps.
-
Рядом с GitHub App, с которым вы хотите работать, нажмите кнопку Изменить.
-
На странице параметров приложения найдите идентификатор клиента для приложения. Вы добавите его в
.env
файл на следующем шаге. Обратите внимание, что идентификатор клиента отличается от идентификатора приложения. -
На странице параметров приложения щелкните Создать новый секрет клиента. Секрет клиента будет добавлен в
.env
файл на следующем шаге. -
Создайте файл с именем
.env
на том же уровне, что и .Gemfile
-
Если в проекте еще
.gitignore
нет файла, создайте.gitignore
файл на том же уровне, что и .Gemfile
-
Добавьте
.env
в.gitignore
файл. Это предотвратит случайную фиксацию секрета клиента. Дополнительные сведения о.gitignore
файлах см. в разделе Пропуск файлов. -
Добавьте в файл следующее содержимое
.env
. ЗаменитеYOUR_CLIENT_ID
идентификатором клиента приложения. ЗаменитеYOUR_CLIENT_SECRET
секретом клиента для приложения.CLIENT_ID="YOUR_CLIENT_ID" CLIENT_SECRET="YOUR_CLIENT_SECRET"
Добавление кода для создания маркера доступа пользователя
Чтобы получить маркер доступа пользователя, сначала необходимо предложить пользователю авторизовать приложение. Когда пользователь авторизует приложение, он перенаправляется на URL-адрес обратного вызова приложения. Запрос к URL-адресу обратного вызова включает code
параметр запроса. Когда приложение получает запрос на обслуживание этого URL-адреса обратного code
вызова, вы можете обменять параметр на маркер доступа пользователя.
Эти действия поведут вас к написанию кода для создания маркера доступа пользователя. Чтобы перейти к окончательному коду, см. раздел Полный пример кода.
-
В том же каталоге, что и файл
.env
, создайте файл Ruby для хранения кода, который создаст маркер доступа пользователя. В этом руководстве файлуapp.rb
будет присвоено имя . -
В верхней части
app.rb
добавьте следующие зависимости:Ruby require "sinatra" require "dotenv/load" require "net/http" require "json"
Зависимости
sinatra
иdotenv/load
используют ранее установленные драгоценные камни.net/http
иjson
являются частью стандартной библиотеки Ruby. -
Добавьте следующий код в
app.rb
, чтобы получить идентификатор клиента и секрет клиента приложения из файла.env
.Ruby CLIENT_ID = ENV.fetch("CLIENT_ID") CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")
-
Добавьте следующий код в ,
app.rb
чтобы отобразить ссылку, которая предложит пользователям пройти проверку подлинности приложения.Ruby get "/" do link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>' erb link end
-
Добавьте следующий код в для
app.rb
обработки запросов к URL-адресу обратногоcode
вызова приложения и получения параметра из запроса. ЗаменитеCALLBACK_URL
URL-адресом обратного вызова для приложения за вычетом домена. Например, если url-адрес обратного вызова —http://localhost:4567/github/callback
, заменитеCALLBACK_URL
на/github/callback
.Ruby get "CALLBACK_URL" do code = params["code"] render = "Successfully authorized! Got code #{code}." erb render end
В настоящее время код просто отображает сообщение вместе с параметром
code
. Следующие шаги раскроют этот блок кода. -
При необходимости проверка ход выполнения:
app.rb
теперь выглядит следующим образом, гдеCALLBACK_URL
— ЭТО URL-адрес обратного вызова для приложения за вычетом домена:Ruby require "sinatra" require "dotenv/load" require "net/http" require "json" CLIENT_ID = ENV.fetch("CLIENT_ID") CLIENT_SECRET = ENV.fetch("CLIENT_SECRET") get "/" do link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>' erb link end get "CALLBACK_URL" do code = params["code"] render = "Successfully authorized! Got code #{code}." erb render end
-
В терминале в каталоге, где
app.rb
хранится , выполните командуruby app.rb
. Должен запуститься локальный сервер Sinatra. -
В браузере перейдите по адресу
http://localhost:4567
. Вы увидите ссылку с текстом "Вход с помощью GitHub". -
Щелкните ссылку "Вход с помощью GitHub".
Если вы не авторизовать приложение, щелкнув ссылку, вы перейдете к
http(s)://HOSTNAME/login/oauth/authorize?client_id=CLIENT_ID
, гдеCLIENT_ID
— это идентификатор клиента вашего приложения. Это страница GitHub, на которую пользователям предлагается авторизовать приложение. Если вы нажмете кнопку для авторизации приложения, вы перейдете по URL-адресу обратного вызова приложения.Если вы ранее авторизовывали приложение и авторизация не была отозвана, вы пропустите запрос авторизации и перейдете непосредственно к URL-адресу обратного вызова. Вы можете отозвать предыдущую авторизацию, если хотите увидеть запрос на авторизацию. Дополнительные сведения см. в разделе Просмотр и отзыв авторизации приложений GitHub.
-
На странице URL-адреса обратного вызова, на которую можно перейти, щелкнув ссылку "Войти с помощью GitHub", а затем авторизовать приложение при появлении соответствующего запроса, должен отобразиться текст, похожий на "Успешно авторизовано! Получил код agc622abb6135be5d1f2.
-
В терминале, где работает Sinatra, остановите сервер, нажав клавиши CTRL+C.
-
-
Замените содержимое
app.rb
следующим кодом, гдеCALLBACK_URL
— ЭТО URL-адрес обратного вызова для вашего приложения за вычетом домена.Этот код добавляет логику для обмена параметром
code
для маркера доступа пользователя:- Функция
parse_response
анализирует ответ из API GitHub. - Функция
exchange_code
обмениваетcode
параметр на маркер доступа пользователя. - Обработчик запроса URL-адреса обратного вызова теперь вызывает
exchange_code
для обмена параметром кода на маркер доступа пользователя. - На странице обратного вызова теперь отображается текст, указывающий, что маркер был создан. Если создание маркера не было успешным, на странице будет указано, что сбой.
Ruby require "sinatra" require "dotenv/load" require "net/http" require "json" CLIENT_ID = ENV.fetch("CLIENT_ID") CLIENT_SECRET = ENV.fetch("CLIENT_SECRET") def parse_response(response) case response when Net::HTTPOK JSON.parse(response.body) else puts response puts response.body {} end end def exchange_code(code) params = { "client_id" => CLIENT_ID, "client_secret" => CLIENT_SECRET, "code" => code } result = Net::HTTP.post( URI("http(s)://HOSTNAME/login/oauth/access_token"), URI.encode_www_form(params), {"Accept" => "application/json"} ) parse_response(result) end get "/" do link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>' erb link end get "CALLBACK_URL" do code = params["code"] token_data = exchange_code(code) if token_data.key?("access_token") token = token_data["access_token"] render = "Successfully authorized! Got code #{code} and exchanged it for a user access token ending in #{token[-9..-1]}." erb render else render = "Authorized, but unable to exchange code #{code} for token." erb render end end
- Функция
-
При необходимости проверка ход выполнения:
- В терминале в каталоге, где
app.rb
хранится , выполните командуruby app.rb
. Должен запуститься локальный сервер Sinatra. - В браузере перейдите по адресу
http://localhost:4567
. Вы увидите ссылку с текстом "Вход с помощью GitHub". - Щелкните ссылку "Вход с помощью GitHub".
- Если появится запрос на это, авторизуйте приложение.
- На странице URL-адреса обратного вызова, на которую можно перейти, щелкнув ссылку "Войти с помощью GitHub", а затем авторизовать приложение при появлении соответствующего запроса, должен отображаться текст, похожий на "Успешно авторизовано! Получил код 4acd44861aeda86dacce и обменял его на маркер доступа пользователя, заканчивающийся на 2zU5kQziE".
- В терминале, где работает Sinatra, остановите сервер, введя клавиши CTRL+C.
- В терминале в каталоге, где
-
Теперь, когда у вас есть маркер доступа пользователя, вы можете использовать его для выполнения запросов API от имени пользователя. Пример:
Добавьте эту функцию в ,
app.rb
чтобы получить сведения о пользователе с помощью конечной/user
точки REST API:Ruby def user_info(token) uri = URI("http(s)://HOSTNAME/api/v3/user") result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| body = {"access_token" => token}.to_json auth = "Bearer #{token}" headers = {"Accept" => "application/json", "Content-Type" => "application/json", "Authorization" => auth} http.send_request("GET", uri.path, body, headers) end parse_response(result) end
Обновите обработчик обратного вызова, чтобы вызвать функцию
user_info
и отобразить имя пользователя и имя входа GitHub. Не забудьте заменитьCALLBACK_URL
URL-адресом обратного вызова для приложения, за исключением домена.Ruby get "CALLBACK_URL" do code = params["code"] token_data = exchange_code(code) if token_data.key?("access_token") token = token_data["access_token"] user_info = user_info(token) handle = user_info["login"] name = user_info["name"] render = "Successfully authorized! Welcome, #{name} (#{handle})." erb render else render = "Authorized, but unable to exchange code #{code} for token." erb render end end
-
Проверьте код по полному примеру кода в следующем разделе. Вы можете протестировать код, выполнив действия, описанные в разделе "Тестирование" под полным примером кода.
Полный пример кода
Это полный пример кода, описанный в предыдущем разделе.
Замените CALLBACK_URL
URL-адресом обратного вызова для приложения, за исключением домена. Например, если url-адрес обратного вызова — http://localhost:4567/github/callback
, замените на CALLBACK_URL
/github/callback
.
require "sinatra"
require "dotenv/load"
require "net/http"
require "json"
CLIENT_ID = ENV.fetch("CLIENT_ID")
CLIENT_SECRET = ENV.fetch("CLIENT_SECRET")
def parse_response(response)
case response
when Net::HTTPOK
JSON.parse(response.body)
else
puts response
puts response.body
{}
end
end
def exchange_code(code)
params = {
"client_id" => CLIENT_ID,
"client_secret" => CLIENT_SECRET,
"code" => code
}
result = Net::HTTP.post(
URI("http(s)://HOSTNAME/login/oauth/access_token"),
URI.encode_www_form(params),
{"Accept" => "application/json"}
)
parse_response(result)
end
def user_info(token)
uri = URI("http(s)://HOSTNAME/api/v3/user")
result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
body = {"access_token" => token}.to_json
auth = "Bearer #{token}"
headers = {"Accept" => "application/json", "Content-Type" => "application/json", "Authorization" => auth}
http.send_request("GET", uri.path, body, headers)
end
parse_response(result)
end
get "/" do
link = '<a href="http(s)://HOSTNAME/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>'
erb link
end
get "CALLBACK_URL" do
code = params["code"]
token_data = exchange_code(code)
if token_data.key?("access_token")
token = token_data["access_token"]
user_info = user_info(token)
handle = user_info["login"]
name = user_info["name"]
render = "Successfully authorized! Welcome, #{name} (#{handle})."
erb render
else
render = "Authorized, but unable to exchange code #{code} for token."
erb render
end
end
Тестирование
В этом руководстве предполагается, что код приложения хранится в файле с именем app.rb
и используется URL-адрес по умолчанию для локального приложения Sinatra. http://localhost:4567
-
В терминале из каталога, в котором
app.rb
хранится, выполните командуruby app.rb
. Должен запуститься локальный сервер Sinatra. -
В браузере перейдите по адресу
http://localhost:4567
. Вы увидите ссылку с текстом "Вход с помощью GitHub". -
Щелкните ссылку "Вход с помощью GitHub".
Если вы не авторизовать приложение, щелкните ссылку, чтобы перейти к
http(s)://HOSTNAME/login/oauth/authorize?client_id=CLIENT_ID
, гдеCLIENT_ID
— это идентификатор клиента вашего приложения. Это страница GitHub, на которую пользователям предлагается авторизовать приложение. Если нажать кнопку для авторизации приложения, вы перейдете по URL-адресу обратного вызова приложения.Если вы ранее авторизовали приложение и авторизация не была отозвана, вы пропустите запрос авторизации и перейдете непосредственно по URL-адресу обратного вызова. Вы можете отозвать предыдущую авторизацию, если хотите увидеть запрос авторизации. Дополнительные сведения см. в разделе Просмотр и отзыв авторизации приложений GitHub.
-
На странице URL-адреса обратного вызова, на которую можно перейти, щелкнув ссылку "Войти с помощью GitHub", а затем авторизовать приложение при появлении соответствующего запроса, должен отображаться текст, похожий на "Успешно авторизовано! Добро пожаловать, Мона Лиза (октокат)."
-
В терминале, где работает Sinatra, остановите сервер, введя клавиши CTRL+C.
Дальнейшие действия
Безопасное хранение секрета клиента
Никогда не следует обнародовать секрет клиента приложения. В этом руководстве секрет клиента хранится в gitignored .env
файле и обращается к значению с помощью ENV.fetch
. При развертывании приложения следует выбрать безопасный способ хранения секрета клиента и обновить код, чтобы получить соответствующее значение.
Например, секрет можно сохранить в переменной среды на сервере, где развернуто приложение. Вы также можете использовать службу управления секретами, например Azure Key Vault.
Обновление URL-адреса обратного вызова для развертывания
В этом руководстве использовался URL-адрес обратного вызова, начинающийся с http://localhost:4567
. http://localhost:4567
Однако он доступен только локально на компьютере при запуске сервера Sinatra. Перед развертыванием приложения необходимо обновить URL-адрес обратного вызова, чтобы использовать URL-адрес обратного вызова, используемый в рабочей среде. Дополнительные сведения об обновлении URL-адреса обратного вызова для приложения см. в разделах Изменение приложения GitHub и Сведения о URL-адресе обратного вызова авторизации пользователя.
Обработка нескольких URL-адресов обратного вызова
В этом руководстве используется один URL-адрес обратного вызова, но в приложении может быть до 10 URL-адресов обратного вызова. Если вы хотите использовать несколько URL-адресов обратного вызова:
- Добавьте в приложение дополнительные URL-адреса обратного вызова. Дополнительные сведения о добавлении URL-адресов обратного вызова см. в разделе Изменение приложения GitHub.
- При связывании
redirect_uri
сhttp(s)://HOSTNAME/login/oauth/authorize
используйте параметр запроса, чтобы перенаправлять пользователей на нужный URL-адрес обратного вызова. Дополнительные сведения см. в разделе Создание маркера доступа пользователя для Приложение GitHub. - В коде приложения обработайте каждый URL-адрес обратного вызова, как и блок кода, начинающийся с
get "CALLBACK_URL" do
.
Указание дополнительных параметров
При связывании с http(s)://HOSTNAME/login/oauth/authorize
можно передать дополнительные параметры запроса. Дополнительные сведения см. в разделе Создание маркера доступа пользователя для Приложение GitHub.
В отличие от традиционного маркера OAuth, маркер доступа пользователя не использует области, поэтому вы не можете указать области с помощью scope
параметра . Вместо этого он использует детализированные разрешения. Маркер доступа пользователя имеет только те разрешения, которые есть как у пользователя, так и у приложения.
Настройка кода в соответствии с потребностями приложения
В этом руководстве показано, как отобразить сведения о пользователе, прошедшем проверку подлинности, но вы можете настроить этот код для выполнения других действий. Не забудьте обновить разрешения приложения, если приложению требуются дополнительные разрешения для запросов API, которые вы хотите выполнить. Дополнительные сведения см. в разделе Выбор разрешений для Приложение GitHub.
В этом руководстве весь код хранится в одном файле, но может потребоваться переместить функции и компоненты в отдельные файлы.
Безопасное хранение маркеров
В этом руководстве создается маркер доступа пользователя. Если вы не отказались от истечения срока действия маркеров доступа пользователей, срок действия маркера доступа пользователя истечет через восемь часов. Вы также получите маркер обновления, который может повторно создать маркер доступа пользователя. Дополнительные сведения см. в разделе Обновление маркеров доступа пользователей.
Если вы планируете дальше взаимодействовать с API GitHub, следует сохранить маркер для использования в будущем. Если вы решили сохранить маркер доступа пользователя или маркер обновления, необходимо сохранить его в безопасном хранилище. Никогда не следует обнародовать маркер.