mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-25 09:48:32 +02:00
migrated from logrus to zerolog, improved error formatting, fixed concurrent map write, fixed crash on rapid page refresh for idle containers, fixed infinite recursion on gotfiy error, fixed websocket connection problem when using idlewatcher
This commit is contained in:
@@ -1,129 +1,117 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
// import (
|
||||
// "encoding/json"
|
||||
// "fmt"
|
||||
// "net/http"
|
||||
// "net/url"
|
||||
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
)
|
||||
// E "github.com/yusing/go-proxy/internal/error"
|
||||
// )
|
||||
|
||||
type oAuth2 struct {
|
||||
*oAuth2Opts
|
||||
m *Middleware
|
||||
}
|
||||
// type oAuth2 struct {
|
||||
// oAuth2Opts
|
||||
// m *Middleware
|
||||
// }
|
||||
|
||||
type oAuth2Opts struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
AuthURL string // Authorization Endpoint
|
||||
TokenURL string // Token Endpoint
|
||||
}
|
||||
// type oAuth2Opts struct {
|
||||
// ClientID string `validate:"required"`
|
||||
// ClientSecret string `validate:"required"`
|
||||
// AuthURL string `validate:"required"` // Authorization Endpoint
|
||||
// TokenURL string `validate:"required"` // Token Endpoint
|
||||
// }
|
||||
|
||||
var OAuth2 = &oAuth2{
|
||||
m: &Middleware{withOptions: NewAuthentikOAuth2},
|
||||
}
|
||||
// var OAuth2 = &oAuth2{
|
||||
// m: &Middleware{withOptions: NewAuthentikOAuth2},
|
||||
// }
|
||||
|
||||
func NewAuthentikOAuth2(opts OptionsRaw) (*Middleware, E.Error) {
|
||||
oauth := new(oAuth2)
|
||||
oauth.m = &Middleware{
|
||||
impl: oauth,
|
||||
before: oauth.handleOAuth2,
|
||||
}
|
||||
oauth.oAuth2Opts = &oAuth2Opts{}
|
||||
err := Deserialize(opts, oauth.oAuth2Opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := E.NewBuilder("missing required fields")
|
||||
optV := reflect.ValueOf(oauth.oAuth2Opts)
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeFor[oAuth2Opts]()) {
|
||||
if optV.FieldByName(field.Name).Len() == 0 {
|
||||
b.Add(E.Missing(field.Name))
|
||||
}
|
||||
}
|
||||
if b.HasError() {
|
||||
return nil, b.Build().Subject("oAuth2")
|
||||
}
|
||||
return oauth.m, nil
|
||||
}
|
||||
// func NewAuthentikOAuth2(opts OptionsRaw) (*Middleware, E.Error) {
|
||||
// oauth := new(oAuth2)
|
||||
// oauth.m = &Middleware{
|
||||
// impl: oauth,
|
||||
// before: oauth.handleOAuth2,
|
||||
// }
|
||||
// err := Deserialize(opts, &oauth.oAuth2Opts)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return oauth.m, nil
|
||||
// }
|
||||
|
||||
func (oauth *oAuth2) handleOAuth2(next http.HandlerFunc, rw ResponseWriter, r *Request) {
|
||||
// Check if the user is authenticated (you may use session, cookie, etc.)
|
||||
if !userIsAuthenticated(r) {
|
||||
// TODO: Redirect to OAuth2 auth URL
|
||||
http.Redirect(rw, r, fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&response_type=code",
|
||||
oauth.oAuth2Opts.AuthURL, oauth.oAuth2Opts.ClientID, ""), http.StatusFound)
|
||||
return
|
||||
}
|
||||
// func (oauth *oAuth2) handleOAuth2(next http.HandlerFunc, rw ResponseWriter, r *Request) {
|
||||
// // Check if the user is authenticated (you may use session, cookie, etc.)
|
||||
// if !userIsAuthenticated(r) {
|
||||
// // TODO: Redirect to OAuth2 auth URL
|
||||
// http.Redirect(rw, r, fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&response_type=code",
|
||||
// oauth.oAuth2Opts.AuthURL, oauth.oAuth2Opts.ClientID, ""), http.StatusFound)
|
||||
// return
|
||||
// }
|
||||
|
||||
// If you have a token in the query string, process it
|
||||
if code := r.URL.Query().Get("code"); code != "" {
|
||||
// Exchange the authorization code for a token here
|
||||
// Use the TokenURL and authenticate the user
|
||||
token, err := exchangeCodeForToken(code, oauth.oAuth2Opts, r.RequestURI)
|
||||
if err != nil {
|
||||
// handle error
|
||||
http.Error(rw, "failed to get token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
// // If you have a token in the query string, process it
|
||||
// if code := r.URL.Query().Get("code"); code != "" {
|
||||
// // Exchange the authorization code for a token here
|
||||
// // Use the TokenURL and authenticate the user
|
||||
// token, err := exchangeCodeForToken(code, &oauth.oAuth2Opts, r.RequestURI)
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// http.Error(rw, "failed to get token", http.StatusUnauthorized)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Save token and user info based on your requirements
|
||||
saveToken(rw, token)
|
||||
// // Save token and user info based on your requirements
|
||||
// saveToken(rw, token)
|
||||
|
||||
// Redirect to the originally requested URL
|
||||
http.Redirect(rw, r, "/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
// // Redirect to the originally requested URL
|
||||
// http.Redirect(rw, r, "/", http.StatusFound)
|
||||
// return
|
||||
// }
|
||||
|
||||
// If user is authenticated, go to the next handler
|
||||
next(rw, r)
|
||||
}
|
||||
// // If user is authenticated, go to the next handler
|
||||
// next(rw, r)
|
||||
// }
|
||||
|
||||
func userIsAuthenticated(r *http.Request) bool {
|
||||
// Example: Check for a session or cookie
|
||||
session, err := r.Cookie("session_token")
|
||||
if err != nil || session.Value == "" {
|
||||
return false
|
||||
}
|
||||
// Validate the session_token if necessary
|
||||
return true
|
||||
}
|
||||
// func userIsAuthenticated(r *http.Request) bool {
|
||||
// // Example: Check for a session or cookie
|
||||
// session, err := r.Cookie("session_token")
|
||||
// if err != nil || session.Value == "" {
|
||||
// return false
|
||||
// }
|
||||
// // Validate the session_token if necessary
|
||||
// return true
|
||||
// }
|
||||
|
||||
func exchangeCodeForToken(code string, opts *oAuth2Opts, requestURI string) (string, error) {
|
||||
// Prepare the request body
|
||||
data := url.Values{
|
||||
"client_id": {opts.ClientID},
|
||||
"client_secret": {opts.ClientSecret},
|
||||
"code": {code},
|
||||
"grant_type": {"authorization_code"},
|
||||
"redirect_uri": {requestURI},
|
||||
}
|
||||
resp, err := http.PostForm(opts.TokenURL, data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to request token: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("received non-ok status from token endpoint: %s", resp.Status)
|
||||
}
|
||||
// Decode the response
|
||||
var tokenResp struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||
return "", fmt.Errorf("failed to decode token response: %w", err)
|
||||
}
|
||||
return tokenResp.AccessToken, nil
|
||||
}
|
||||
// func exchangeCodeForToken(code string, opts *oAuth2Opts, requestURI string) (string, error) {
|
||||
// // Prepare the request body
|
||||
// data := url.Values{
|
||||
// "client_id": {opts.ClientID},
|
||||
// "client_secret": {opts.ClientSecret},
|
||||
// "code": {code},
|
||||
// "grant_type": {"authorization_code"},
|
||||
// "redirect_uri": {requestURI},
|
||||
// }
|
||||
// resp, err := http.PostForm(opts.TokenURL, data)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("failed to request token: %w", err)
|
||||
// }
|
||||
// defer resp.Body.Close()
|
||||
// if resp.StatusCode != http.StatusOK {
|
||||
// return "", fmt.Errorf("received non-ok status from token endpoint: %s", resp.Status)
|
||||
// }
|
||||
// // Decode the response
|
||||
// var tokenResp struct {
|
||||
// AccessToken string `json:"access_token"`
|
||||
// }
|
||||
// if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
||||
// return "", fmt.Errorf("failed to decode token response: %w", err)
|
||||
// }
|
||||
// return tokenResp.AccessToken, nil
|
||||
// }
|
||||
|
||||
func saveToken(rw ResponseWriter, token string) {
|
||||
// Example: Save token in cookie
|
||||
http.SetCookie(rw, &http.Cookie{
|
||||
Name: "auth_token",
|
||||
Value: token,
|
||||
// set other properties as necessary, such as Secure and HttpOnly
|
||||
})
|
||||
}
|
||||
// func saveToken(rw ResponseWriter, token string) {
|
||||
// // Example: Save token in cookie
|
||||
// http.SetCookie(rw, &http.Cookie{
|
||||
// Name: "auth_token",
|
||||
// Value: token,
|
||||
// // set other properties as necessary, such as Secure and HttpOnly
|
||||
// })
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user