Added authentication middleware
This commit is contained in:
@@ -1,21 +1,105 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
"projectreshoot/config"
|
||||
"projectreshoot/contexts"
|
||||
"projectreshoot/cookies"
|
||||
"projectreshoot/db"
|
||||
"projectreshoot/jwt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// Take current request
|
||||
// Get cookies from browser
|
||||
// Parse the tokens
|
||||
// Check if tokens blacklisted
|
||||
// Trigger refresh if required
|
||||
// Create context with state of user authorization
|
||||
// Pass request on with context
|
||||
// Attempt to use a valid refresh token to generate a new token pair
|
||||
func refreshAuthTokens(
|
||||
config *config.Config,
|
||||
conn *sql.DB,
|
||||
w http.ResponseWriter,
|
||||
req *http.Request,
|
||||
ref *jwt.RefreshToken,
|
||||
) (*db.User, error) {
|
||||
user, err := ref.GetUser(conn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rT.GetUser")
|
||||
}
|
||||
|
||||
func Authentication(logger *zerolog.Logger, next http.Handler) http.Handler {
|
||||
rememberMe := map[string]bool{
|
||||
"session": false,
|
||||
"exp": true,
|
||||
}[ref.TTL]
|
||||
|
||||
// Set fresh to true because new tokens coming from refresh request
|
||||
err = cookies.SetTokenCookies(w, req, config, user, false, rememberMe)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cookies.SetTokenCookies")
|
||||
}
|
||||
// New tokens sent, revoke the used refresh token
|
||||
err = jwt.RevokeToken(conn, ref)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jwt.RevokeToken")
|
||||
}
|
||||
// Return the authorized user
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// Check the cookies for token strings and attempt to authenticate them
|
||||
func getAuthenticatedUser(
|
||||
config *config.Config,
|
||||
conn *sql.DB,
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) (*db.User, error) {
|
||||
// Get token strings from cookies
|
||||
atStr, rtStr := cookies.GetTokenStrings(r)
|
||||
// Attempt to parse the access token
|
||||
aT, err := jwt.ParseAccessToken(config, conn, atStr)
|
||||
if err != nil {
|
||||
// Access token invalid, attempt to parse refresh token
|
||||
rT, err := jwt.ParseRefreshToken(config, conn, rtStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jwt.ParseRefreshToken")
|
||||
}
|
||||
// Refresh token valid, attempt to get a new token pair
|
||||
user, err := refreshAuthTokens(config, conn, w, r, &rT)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "refreshAuthTokens")
|
||||
}
|
||||
// New token pair sent, return the authorized user
|
||||
return user, nil
|
||||
}
|
||||
// Access token valid
|
||||
user, err := aT.GetUser(conn)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rT.GetUser")
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// Attempt to authenticate the user and add their account details
|
||||
// to the request context
|
||||
func Authentication(
|
||||
logger *zerolog.Logger,
|
||||
config *config.Config,
|
||||
conn *sql.DB,
|
||||
next http.Handler,
|
||||
) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
user, err := getAuthenticatedUser(config, conn, w, r)
|
||||
if err != nil {
|
||||
// User auth failed, delete the cookies to avoid repeat requests
|
||||
cookies.DeleteCookie(w, "access", "/")
|
||||
cookies.DeleteCookie(w, "refresh", "/")
|
||||
logger.Debug().
|
||||
Str("remote_addr", r.RemoteAddr).
|
||||
Err(err).
|
||||
Msg("Failed to authenticate user")
|
||||
}
|
||||
ctx := contexts.SetUser(r.Context(), user)
|
||||
newReq := r.WithContext(ctx)
|
||||
next.ServeHTTP(w, newReq)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ func Logging(logger *zerolog.Logger, next http.Handler) http.Handler {
|
||||
Int("status", wrapped.statusCode).
|
||||
Str("method", r.Method).
|
||||
Str("resource", r.URL.Path).
|
||||
Dur("time_elapsed", time.Since(start)).Msg("Served")
|
||||
Dur("time_elapsed", time.Since(start)).
|
||||
Str("remote_addr", r.RemoteAddr).
|
||||
Msg("Served")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user