@ -346,15 +346,76 @@ func handleUserSignupPost(logger *slog.Logger, tc *TemplateCache, fd *form.Decod
} )
}
func handleUserLoginGet ( ) http . Handler {
func handleUserLoginGet ( tc * TemplateCache , sm * scs . SessionManager ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , "Displaying loging form for user" )
data := newTemplateData ( r , sm )
data . Form = userLoginForm { }
renderTemplate ( w , r , tc , http . StatusOK , "login.go.tmpl" , data )
} )
}
func handleUserLoginPost ( ) http . Handler {
func handleUserLoginPost ( logger * slog . Logger , tc * TemplateCache , sm * scs . SessionManager , fd * form . Decoder , userService * model . UserService ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , "Authenticate and login user" )
// parse form
err := r . ParseForm ( )
if err != nil {
logger . Error ( "Failed to parse login form" )
clientError ( w , http . StatusBadRequest )
return
}
form := userLoginForm { }
err = decodePostForm ( r , fd , & form )
if err != nil {
logger . Error ( "Failed to decode login form" )
clientError ( w , http . StatusBadRequest )
return
}
form . CheckField ( validator . NotBlank ( form . Email ) , "email" , "This field cannot be blank" )
form . CheckField ( validator . Matches ( form . Email , validator . EmailRX ) , "email" , "This field must be a valid email" )
form . CheckField ( validator . NotBlank ( form . Password ) , "password" , "This field cannot be blank" )
if ! form . Valid ( ) {
logger . Info ( "An invalid form was submitted" )
data := newTemplateData ( r , sm )
data . Form = form
renderTemplate ( w , r , tc , http . StatusUnprocessableEntity , "login.go.tmpl" , data )
return
}
id , err := userService . Authenticate ( form . Email , form . Password )
if err != nil {
if errors . Is ( err , model . ErrInvalidCredentials ) {
form . AddNonFieldError ( "Email or password is incorrect" )
data := newTemplateData ( r , sm )
data . Form = form
renderTemplate ( w , r , tc , http . StatusUnprocessableEntity , "login.go.tmpl" , data )
} else {
serverError ( w , r , err )
}
return
}
// Use the RenewToken() method on the current session to change the session ID.
// It's good practice to generate a new session ID when the authentication state
// or privilege levels change for the user (e.g. login and logout operations)
// This changes the ID of the current user’ s session but retain any data
// associated with the session
// see https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Session_Management_Cheat_Sheet.md#renew-the-session-id-after-any-privilege-level-change
err = sm . RenewToken ( r . Context ( ) )
if err != nil {
serverError ( w , r , err )
return
}
// Add the ID of the current user to the session, so that they are now "logged in"
sm . Put ( r . Context ( ) , "authenticatedUserID" , id )
http . Redirect ( w , r , "/snippet/create" , http . StatusSeeOther )
} )
}