Репозиторий проекта: здесь.
Общее описание
Данный модуль содержит механизм авторизации некоторого веб-приложения с получением данных о пользователе с помощью протокола OAuth2 через различные сервисы, поддерживающие этот протокол. В дальнейшем формируются куки с информацией о пользователе и CSRF-токеном. CSRF-токен простого типа, действует в пределах работы программы на сервере.
Основу всего механизма составляет объект типа OAuthCollect
, который содержит экземпляры интерфейсов OAuthorizator
. Интерфейс OAuthorizator описывает каждый отдельный сервис авторизации (Yandex, Google и т. д.). Смысл в том, чтобы получить данные о пользователе (его идентификатор в сервисе, поддерживающим OAuth, его имя и адрес электронной почты).
Записать их в базу данных и выдать некоторый токен. Пока есть токен — считать, что пользователь авторизован. Если токена нет — повторно его авторизовывать через OAuth.
Использование OAuthCollect
OAuthCollect содержит функцию инициализации Init()
. Её нужно вызвать в первую очередь.
Эта функция имеет следующие параметры:
- VerificationCodeCallbackURL — тип string, в данном аргументе необходимо указать,
по какому адресу сервер авторизации должен передать код авторизации. - DoneAuthUrl — тип string, в данном аргументе необходимо указать, какую страницу показать
пользователю по окончании авторизации. - OnlyHttps — данный аргумент указывает, нужно ли передавать куки только по защищённому протоколу или нет.
Для добавления конкретных сервисов авторизации необходимо вызывать функцию AddService()
. В качестве аргумента в неё передаётся объект соответствующий интерфейсу OAuthorizator.
Точкой старта процедуры инициализации является один из адресов (страница входа), который присваивается кнопке или ссылке. Эти адреса, принадлежащие каждому определённому сервису передаются в один из JS-скриптов в виде констант. Текст объявления констант получаем с помощью третьей функции GetSettingsJS()
. Текст объявления адреса входа каждого сервиса имеет вид:
const OAUTH_%1_URL = "%2";
, где
- %1 — имя сервиса капсом (YANDEX, GOOGLE и т. п.)
- %2 — сам адрес (URL)
Полный пример использования выглядит так:
package main
// Раздел импорта
import (
"fmt"
"net/http"
"bitbucket.org/aaklenov/oauth"
"bitbucket.org/aaklenov/oauth_google"
)
var g_oauth oauth.OAuthCollect
func main() {
err := g_oauth.Init("http://example.com:9000/oauth_verification_code", "http://example.com:9000", true)
oauth_go := OAuthGoogle { // oauth_google.
ClientId: "xxx.apps.googleusercontent.com",
ClientSecret: "yyy",
}
g_oauth.AddService(&oauth_go)
http.HandleFunc("/", HomeRouterHandler)
err = http.ListenAndServe(":9000", nil)
if err != nil {
fmt.Println("ListenAndServe: ", err)
}
}
func HomeRouterHandler(w http.ResponseWriter, r *http.Request) {
if (r.URL.Path == "/js/settings.js") {
oauth_settings := g_oauth.GetSettingsJS()
fmt.Fprintf(w, oauth_settings)
}
}
Интерфейс OAuthorizator
Объект интерфейса должен содержать три функции:
type OAuthorizator interface {
ServiceName() (string)
LoginURL(verification_code_callback_url string, state string) (string)
OnRecieveVerificationCode(code string, u *UserData) (error)
}
Функция ServiceName()
должна возвращать имя сервиса, например: google.
Функция LoginURL()
должна возвращать адрес страницы, на которой пользователя спросят, разрешает он или нет такому-то веб-приложению доступ к имени и электронной почте. В ней передаётся адрес веб-приложения, куда нужно передать код авторизации. А также передаётся state
— строка, которую нужно записать в одноимённый get-параметр адреса. В этой строке содержится имя сервиса и специальный токен, который помогает определить, что вызов по адресу verification_code_callback_url
исходит именно от OAuth-сервиса, и соответственно параметры, передаваемые в нём, не нанесут вред (впрочем, значения параметров нигде не сохраняются и обычно передаются обратно в сервис "как есть").
Функция OnRecieveVerificationCode()
вызывается, когда получен код авторизации и он проверен, что это именно он, а не посторонний вызов. При получении кода авторизации экземпля интерфейса должен запросить токен. А далее по токену — получить данные пользователя и передать их в структуру oauth.UserData
. К заполнению требуется следующие поля:
- ExtId, тип string — содержит идентификатор клиента в сервисе
- Name, тип string — содержит имя пользователя
- Email, тип string — содержит адрес электронной почты пользователя
Содержимое структуры:
type UserData struct {
UserId int64
Name string
Email string
ExtId string
OAuthServiceName string
}