Создание сайта с GitHub авторизацией на Buffalo (Golang)

Создание сайта с GitHub авторизацией на Buffalo (Golang)
В этой статье мы рассмотрим создание сайта с Buffalo, в котором пользователи могут авторизовываться с помощью учётной записи GitHub. С помощью встроенных генераторов Buffalo выполнить эту задачу очень просто и вручную нам почти ничего не нужно будет делать.
Скачать полный пример этого урока можно по ссылке.

Проверьте сперва, что у вас установлен Buffalo и npm.

Регистрируем приложение на GitHub

Для начала нам нужно зарегистрировать приложение на GitHub. Для этого перейдите в раздел developer applications и добавьте новое OAuth приложение.

  • в Homepage URL укажите:
    http://127.0.0.1:3000
  • в Authorization callback URL укажите:
    http://127.0.0.1:3000/auth/github

Остальные поля заполните по желанию. После окончания регистрации у вас будут Client ID и Client Secret. Храните их в секрете и никогда не публикуйте!

Создаём проект

Создадим новый проект с указанием флага —skip-pop, это нужно, чтобы наш проект был создан без компонентов базы данных. В этом примере мы сконцентрируемся на авторизации и не будем касаться контента сайта. Итак, создадим проект githubauth:

buffalo new githubauth --skip-pop

Интегрируем goth в наш проект

Для авторизации мы будем использовать goth. Поддержка этого пакета включена в Buffalo и в нём есть генератор для создания базовой структуры. Чтобы добавить функционал авторизации на сайт используйте следующую команду:

buffalo g goth github

Проверка маршрутов

Начнём с actions/app.go:

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() *buffalo.App {
if app == nil {
app = buffalo.Automatic(buffalo.Options{
Env: ENV,
SessionName: "_githubauth_session",
Host: "http://localhost:3000",
})

app.GET(«/», HomeHandler)

app.ServeFiles(«/assets», assetsPath())
auth := app.Group(«/auth»)
auth.GET(«/{provider}», buffalo.WrapHandlerFunc(gothic.BeginAuthHandler))
auth.GET(«/{provider}/callback», AuthCallback)
}


return app
}

Генератор добавил свои маршруты (строки 15-17). Вначале была создана группа auth, а внутри неё добавлен маршрут для авторизации и ещё один для обратного вызова. Оба настроены так, чтобы можно было в дальнейшем использовать множество провайдеров. А в нашем случае в переменной {provider} корректен только github.

При работе с OAuth провайдерами им важно знать обратный адрес, на который возвращать ответ от процесса авторизации. Добавим в конфигурацию опцию Host (строка 9) для указания нашего сервера. В этом примере наш сервер будет доступен по адресу localhost:3000.

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

http://127.0.0.1:3000/auth/github
http://127.0.0.1:3000/auth/github/callback

Проверка авторизации

Рассмотрим файл action/auth.go:

package actions

import (
«fmt»
«os»

«github.com/gobuffalo/buffalo»
«github.com/markbates/goth»
«github.com/markbates/goth/gothic»
«github.com/markbates/goth/providers/github»
)

func init() {
gothic.Store = App().SessionStore

goth.UseProviders(
github.New(os.Getenv(«GITHUB_KEY»), os.Getenv(«GITHUB_SECRET»), fmt.Sprintf(«{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s», App().Host, «/auth/github/callback»)),
)
}


func AuthCallback(c buffalo.Context) error {
user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
if err != nil {
return c.Error(401, err)
}
// Do something with the user, maybe register them/sign them in
return c.Render(200, r.JSON(user))
}

В строке 17 мы задаём Client ID и Client Secret. Генератор берёт их с помощью os.Getenv(). Соответственно, у вас должны быть заданы переменные окружения GITHUB_KEY и GITHUB_SECRET. Если вы не знаете что с ними делать, воспользуйтесь setenv.

Запустим Buffalo в режиме разработки:

buffalo dev

Перейдём по адресу авторизации и посмотрим что там:

http://127.0.0.1:3000/auth/github
Если вы авторизованы на GitHub, то вы сразу сможете авторизоваться и на нашем сайте.

Меняем scope

На данный момент мы не спрашивали никаких разрешений, но если вам необходимо знать больше информации от пользователя, задайте scope. Для GitHub эта тема хорошо документирована. Для получения электронной почты пользователя вызовите goth.UseProviders() следующим образом:

goth.UseProviders(
github.New(
os.Getenv("GITHUB_KEY"),
os.Getenv("GITHUB_SECRET"),
fmt.Sprintf("{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s", App().Host, "/auth/github/callback"),
"user:email"),
)

При заданном scope, GitHub явно спросит пользователя, желает ли он поделиться такой информацией с вашим приложением. Поиграйтесь с этим механизмом и посмотрите как будет меняться страница авторизации.

Создаём сайт

Самое сложное позади, осталось создать сайт вокруг нашего механизма.

Структура сайта будет предельно проста:

  • Главная страница: /
  • Страница входа: /login
  • Безопасное содержимое: /secure

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

Создаём middleware

Для проверки авторизованности пользователя создадим промежуточное приложение.

// CheckAuth is the middlewar to check if a user is logged on.
func CheckAuth(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
// Read the userID out of the session
userID := c.Session().Get("userID")
// If there is no userID redirect to the login page
if userID == nil {
err := c.Redirect(http.StatusTemporaryRedirect, "/login")
return err
}
// If not, call the next handler
err := next(c)
return err
}
}

Создаём безопасные маршруты

Сгруппируем весь безопасный контент:

// Create the secure group
secure := app.Group("/secure")
// Add the middleware CheckAuth to the group
secure.Use(CheckAuth)
// Create a simple secure handler, which renders a html file
secure.GET("/",
func(c buffalo.Context) error {
return c.Render(200, r.HTML("secure/index.html"))
})
// Create a logout action, where the userID inside the session is deleted
secure.DELETE("/logout",
func(c buffalo.Context) error {
session := c.Session()
session.Delete("userID")
session.Save()
return c.Redirect(301, "/login")
})

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

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

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

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

func AuthCallback(c buffalo.Context) error {
user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
if err != nil {
return c.Error(401, err)
}
session := c.Session()
session.Set("userID", user.UserID)
err = session.Save()
if err != nil {
return c.Error(401, err)
}
return c.Redirect(http.StatusMovedPermanently, "/secure")
}

В строках 6-8 user.UserID сохраняется в сессии. В строке 12 перекидываем пользователя на безопасную страницу.

Заключение

Я не буду описывать как создавать страницы в Buffalo, это есть в документации. У нас на текущий момент есть безопасный раздел, куда попадает пользователь после входа. Чтобы добавить ещё один безопасный маршрут, используйте соответствующую группу роутов.

Состояние пользователя (по userID) мы храним в сессии, а если пользователь захочет выйти, мы просто удалим его сессию.

На странице входа будет ссылка “Login with your GitHub Account”, но пакет goth поддерживает множество провайдеров (предполагаю, он поддерживает все подобные сервисы, а в его примерах использования вы найдёте все поддерживаемые службы).

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

buffalo g goth twitter github

С помощью scope вы можете запрашивать любую информацию о пользователе (такую, как почта, аватар, телефон и т.п.), мы описали это выше.

А если вы не хотите заниматься этим, воспользуйтесь сервисом Auth0, который сам всё сделает за вас.

Пример вы можете взять здесь. Внимательно ознакомьтесь с инструкцией по установке.

Источник: «Buffalo Tutorial: Create a site with GitHub Auth»

Leave a Comment