Представляем Dark Mirea Login 
Привет! Мы создали oauth2 сервер, основанный на скрытой аутентификации, который позволяет студентам МИРЭА легко и безопасно авторизовывать пользователей в своих проектах.
Что такое OAuth 2.0? 
OAuth 2.0 - это стандарт авторизации, который позволяет выдавать ограниченный доступ к защищенным ресурсам пользователя на стороннем сервисе или приложении, без необходимости передавать логин и пароль. OAuth 2.0 широко используется такими компаниями как Google, Facebook, Microsoft и многими другими для организации процесса аутентификации.
Возможности Dark Mirea Login 
Наш “Dark Mirea Login” реализует этот протокол в обход login.mirea.ru (с использованием скрытых механизмов) и дает возможность студентам использовать единую учетную запись МИРЭА для входа в различные сервисы и приложения. Это упрощает процесс регистрации и входа для пользователей. А разработчикам больше не нужно реализовывать свою систему аутентификации в каждом проекте.
Вот что можно с этим сделать (идеи):
-
Чат-боты для студентов в Telegram или VK, которые будут ограничивать доступ к публичным чатам (пускать только студентов)
-
Сервис для обмена приватными сообщениями между студентами с возможностью шифрования и ограничения доступа.
-
Платформа для проведения опросов, голосований среди студентов с возможностью ограничения участников по различным критериям.
-
Сервис обмена учебными материалами, где студенты могут делиться конспектами, книгами, решениями задач с доступом только для своей группы или курса.
-
Платформа для поиска команды для проектов или стартапов среди студентов МИРЭА с верификацией профилей через Dark Mirea Login.
-
Онлайн-галерея творческих работ студентов МИРЭА (дизайн, фото, видео) с возможностью комментирования и оценки только для авторизованных пользователей.
-
Доска объявлений о стажировках и вакансиях, доступная только для студентов МИРЭА определенных специальностей и курсов.
-
Различные мобильные приложения для студентов университета.
Технические особенности 
Одна из особенностей нашего решения - публичные oauth-клиенты. Это значит, что параметры client_id
и client_secret
для всех приложений имеют одинаковое значение 'public'
. Таким образом упрощается процесс интеграции, не нужно запрашивать и хранить уникальные ключи.
- Base URL -
https://login.mirea.ninja
- Login URL -
https://login.mirea.ninja/login
Endpoints:
/oauth/authorize
- запрос авторизации/oauth/token
- получение access токена/oauth/userinfo
- получение информации о пользователе
Формат userinfo:
{
"id": 12345,
"name": "Иванов Иван",
"email": "ivanov@mirea.ru",
"group": "ИКБО-01-20",
"personal_number": "12345678",
"full_name": "Иванов Иван Иванович"
}
Пример реализации клиента на Go
- Запустите файл с помощью
go run ...
- Откройте http://localhost:9094/
package main
import (
"context"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
)
const (
authServerURL = "https://login.mirea.ninja"
)
var (
config = oauth2.Config{
ClientID: "public",
ClientSecret: "public",
Scopes: []string{"all"},
RedirectURL: "http://localhost:9094/oauth2",
Endpoint: oauth2.Endpoint{
AuthURL: authServerURL + "/oauth/authorize",
TokenURL: authServerURL + "/oauth/token",
},
}
globalToken *oauth2.Token
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
u := config.AuthCodeURL("xyz",
oauth2.SetAuthURLParam("code_challenge", genCodeChallengeS256("s256example")),
oauth2.SetAuthURLParam("code_challenge_method", "S256"))
w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, `<html><body><a href="%s">Login with MIREA</a></body></html>`, u)
})
http.HandleFunc("/oauth2", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
state := r.Form.Get("state")
if state != "xyz" {
http.Error(w, "State invalid", http.StatusBadRequest)
return
}
code := r.Form.Get("code")
if code == "" {
http.Error(w, "Code not found", http.StatusBadRequest)
return
}
token, err := config.Exchange(context.Background(), code, oauth2.SetAuthURLParam("code_verifier", "s256example"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
globalToken = token
e := json.NewEncoder(w)
e.SetIndent("", " ")
e.Encode(token)
})
http.HandleFunc("/refresh", func(w http.ResponseWriter, r *http.Request) {
if globalToken == nil {
http.Redirect(w, r, "/", http.StatusFound)
return
}
globalToken.Expiry = time.Now()
token, err := config.TokenSource(context.Background(), globalToken).Token()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
globalToken = token
e := json.NewEncoder(w)
e.SetIndent("", " ")
e.Encode(token)
})
http.HandleFunc("/userinfo", func(w http.ResponseWriter, r *http.Request) {
if globalToken == nil {
http.Redirect(w, r, "/", http.StatusFound)
return
}
req, err := http.NewRequest("GET", authServerURL+"/oauth/userinfo", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
req.Header.Set("Authorization", "Bearer "+globalToken.AccessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
})
log.Println("Started...")
log.Fatal(http.ListenAndServe(":9094", nil))
}
func genCodeChallengeS256(s string) string {
s256 := sha256.Sum256([]byte(s))
return base64.URLEncoding.EncodeToString(s256[:])
}
Безопасность превыше всего 
Мы со всей ответственностью подходим к вопросам безопасности и приватности пользовательских данных. Мы не храним логи и пароли пользователей, а также любые другие данные.