Redirect to external login form
This commit is contained in:
parent
4f1b20e392
commit
15fea62a0c
24
api/auth.go
24
api/auth.go
|
@ -127,6 +127,18 @@ func retrieveSessionFromClaims(claims *UserClaims, user *happydns.User, session_
|
|||
return
|
||||
}
|
||||
|
||||
func requireLogin(opts *config.Options, c *gin.Context, msg string) {
|
||||
if opts.ExternalAuth.URL != nil {
|
||||
customurl := *opts.ExternalAuth.URL
|
||||
q := customurl.Query()
|
||||
q.Set("errmsg", msg)
|
||||
customurl.RawQuery = q.Encode()
|
||||
c.Header("Location", customurl.String())
|
||||
}
|
||||
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": msg})
|
||||
}
|
||||
|
||||
func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var token string
|
||||
|
@ -143,7 +155,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
|||
if optional {
|
||||
c.Next()
|
||||
} else {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "No authorization token found in cookie nor in Authorization header."})
|
||||
requireLogin(opts, c, "No authorization token found in cookie nor in Authorization header.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -157,7 +169,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
|||
if err != nil {
|
||||
log.Printf("%s provide a bad JWT claims: %s", c.ClientIP(), err.Error())
|
||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
||||
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -165,14 +177,14 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
|||
if len(claims.Profile.UserId) == 0 {
|
||||
log.Printf("%s: no UserId found in JWT claims", c.ClientIP())
|
||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
||||
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||
return
|
||||
}
|
||||
|
||||
if claims.Profile.Email == "" {
|
||||
log.Printf("%s: no Email found in JWT claims", c.ClientIP())
|
||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
||||
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -181,7 +193,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
|||
if err != nil {
|
||||
log.Printf("%s %s", c.ClientIP(), err.Error())
|
||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
||||
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -193,7 +205,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
|||
if err != nil {
|
||||
log.Printf("%s %s", c.ClientIP(), err.Error())
|
||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Your session has expired. Please reconnect.")})
|
||||
requireLogin(opts, c, "Your session has expired. Please reconnect.")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ func displayAuthToken(c *gin.Context) {
|
|||
|
||||
func displayNotAuthToken(opts *config.Options, c *gin.Context) {
|
||||
if !opts.NoAuth {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "Authorization required"})
|
||||
requireLogin(opts, c, "Authorization required")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ func (o *Options) declareFlags() {
|
|||
flag.Var(&o.StorageEngine, "storage-engine", fmt.Sprintf("Select the storage engine between %v", storage.GetStorageEngines()))
|
||||
flag.BoolVar(&o.NoAuth, "no-auth", false, "Disable user access control, use default account")
|
||||
flag.Var(&o.JWTSecretKey, "jwt-secret-key", "Secret key used to verify JWT authentication tokens (a random secret is used if undefined)")
|
||||
flag.Var(&o.ExternalAuth, "external-auth", "Base URL to use for login and registration (use embedded forms if left empty)")
|
||||
|
||||
// Others flags are declared in some other files likes sources, storages, ... when they need specials configurations
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ type Options struct {
|
|||
// NoAuth controls if there is user access control or not.
|
||||
NoAuth bool
|
||||
|
||||
// ExternalAuth is the URL of the login form to use instead of the embedded one.
|
||||
ExternalAuth URL
|
||||
|
||||
// JWTSecretKey stores the private key to sign and verify JWT tokens.
|
||||
JWTSecretKey JWTSecretKey
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ package config // import "happydns.org/config"
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type JWTSecretKey []byte
|
||||
|
@ -50,3 +51,25 @@ func (i *JWTSecretKey) Set(value string) error {
|
|||
*i = z
|
||||
return nil
|
||||
}
|
||||
|
||||
type URL struct {
|
||||
URL *url.URL
|
||||
}
|
||||
|
||||
func (i *URL) String() string {
|
||||
if i.URL != nil {
|
||||
return i.URL.String()
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (i *URL) Set(value string) error {
|
||||
u, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.URL = u
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -32,10 +32,21 @@
|
|||
import axios from 'axios'
|
||||
|
||||
export default () => {
|
||||
return axios.create({
|
||||
const a = axios.create({
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
a.interceptors.response.use((response) => {
|
||||
return response
|
||||
}, (error) => {
|
||||
if (error.response && error.response.status === 401 && error.response.headers && error.response.headers.location) {
|
||||
window.location = error.response.headers.location
|
||||
}
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
return a
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue