Модуль OAuth

Репозиторий проекта: здесь.

Общее описание

Данный модуль содержит механизм авторизации некоторого веб-приложения с получением данных о пользователе с помощью протокола 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
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *