Raw hardcode cookie and session on my CRUD project not working properly

here’s my code:

`
package main

import (
"database/sql"
"fmt"
"github.com/go-sql-driver/mysql"
"golang.org/x/crypto/bcrypt"
"html/template"
"log"
"net/http"
"strconv"
"time"
)

var (
err   error
db    *sql.DB
templ *template.Template
adtempl *template.Template
//cookie *http.Cookie
ID int64
)

type PageData struct {
Title       string
IsAuth      bool
Id          int
Username    string
Password    string
Description string
Created_at  mysql.NullTime
Updated_at  mysql.NullTime
AdminD      int
}

func init() {
    templ, err = templ.ParseGlob("templates/*.html")
    if err != nil {
	log.Fatalln(err.Error())
}
adtempl, err = adtempl.ParseGlob("templates/admin/*.html")
if err != nil {
	log.Fatalln(err.Error())
    }
}

func main() {
handleDbConnection()
http.HandleFunc("/", index)
http.HandleFunc("/login", login)
//http.HandleFunc("/admin", admin)
http.HandleFunc("/create", createUser)
http.HandleFunc("/read", readUser)
http.HandleFunc("/update", updateUser)
http.HandleFunc("/delete", deleteUser)
http.Handle("/assets/", http.FileServer(http.Dir("."))) //serve other files in assets dir
http.Handle("/favicon.ico", http.NotFoundHandler())
fmt.Println("server running on port :8080")
http.ListenAndServe(":8080", nil)

}

func index(res http.ResponseWriter, req *http.Request) {
cookie, err := req.Cookie("logged-in")
if err == http.ErrNoCookie{
	cookie = &http.Cookie{
		Name: "logged-in",
		Value: "0",
	}
}
title := "Home || cb_net sessions"
var isAuth bool
var pd = PageData{Title: title, IsAuth: isAuth}
if cookie.Value == strconv.Itoa(1) {
	err = adtempl.ExecuteTemplate(res, "index.html", pd)
	if err != nil {
		log.Fatalln(err.Error(),"no admin index")
	}
	fmt.Println("success")
} else if cookie.Value == strconv.Itoa(2) {
	err = templ.ExecuteTemplate(res, "index.html", pd)
	if err != nil {
		log.Fatalln(err.Error(),"no user index")
	}
	fmt.Println("success")
} else {
	isAuth = false
}
err = templ.ExecuteTemplate(res, "index.html", pd)
if err != nil {
	log.Fatalln(err.Error())
}
//pd = append(pd, PageData{Title: title, IsAuth: isAuth})

}

func handleDbConnection() {
// Create an sql.DB and check for errors
db, err = sql.Open("mysql", "root:elemie@/GoStaffManager")
if err != nil {
	panic(err.Error())
}

// Test the connection to the database
err = db.Ping()
if err != nil {
	panic(err.Error())
}
}

func login(res http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
	err = templ.ExecuteTemplate(res, "login.html", nil)
	if err != nil {
		fmt.Sprint("error", err)
	}
	return
}
// query
rows, err := db.Query("SELECT username,password,is_admin FROM new_table")
if err != nil {
	log.Println(err.Error())
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

var username = req.FormValue("username")
password := req.FormValue("password")
var pword string
var isAdmin int
for rows.Next() {
	err = rows.Scan(&username, &pword, &isAdmin)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	if isAdmin == 1 {
		// Validate the password
		err = bcrypt.CompareHashAndPassword([]byte(pword), []byte(password))
		// If wrong password redirect to the login
		if err != nil {
			fmt.Println("invalid")
			http.Redirect(res, req, "/login", 301)
			return
		}
		cookie := &http.Cookie{
			Name: "logged-in",
			Value: "1",
		}
		http.SetCookie(res, cookie)
		http.Redirect(res, req, "/", 302)
		return
	} else {
		// Validate the password
		err = bcrypt.CompareHashAndPassword([]byte(pword), []byte(password))
		// If wrong password redirect to the login
		if err != nil {
			fmt.Println("invalid")
			http.Redirect(res, req, "/login", 301)
			return
		}
		cookie := &http.Cookie{
			Name: "logged-in",
			Value: "2",
		}
		http.SetCookie(res, cookie)
		http.Redirect(res, req, "/", 302)
		return
	}
}

}

func createUser(res http.ResponseWriter, req *http.Request)  {
//insert into db
stmt, err := db.Prepare("INSERT new_table SET username=?, password=?, created_at=?, updated_at=?, is_admin=?")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

if req.Method != "POST" {
	adtempl.ExecuteTemplate(res, "create.html", nil)
	return
}

username  := req.FormValue("username")
password  := req.FormValue("password")
isAdmin   := req.FormValue("admin")
createdAt := time.Now()
updatedAt := time.Now()


var admin_chk int
if isAdmin == "on" {
	admin_chk = 1
} else {
	admin_chk = 0
}

var user string
err = db.QueryRow("SELECT username FROM new_table WHERE username=?", username).Scan(&user)

switch {
//username is available
case err == sql.ErrNoRows:
	securedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	rs, err := stmt.Exec(username, securedPassword, createdAt, updatedAt, admin_chk)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	id, err := rs.LastInsertId()
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}

	ID = getID(id).(int64)
	res.Write([]byte("user successfully created!"))
	fmt.Println("user: ",username," with ID: ",id," successfully created!")
	return
case err != nil:
	http.Error(res, err.Error(), 500)
	return
default:
	http.Redirect(res, req, "/create", 301)
}
}

func readUser(res http.ResponseWriter, req *http.Request)  {
// query
rows, err := db.Query("SELECT * FROM new_table")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

var id int
var username string
var password string
var created_at mysql.NullTime
var updated_at mysql.NullTime
var isAdmin int

/*if req.Method != "POST" {

}*/

var ps []PageData

for rows.Next() {
	err = rows.Scan(&id, &username, &password, &created_at, &updated_at, &isAdmin)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	ps = append(ps, PageData{Id: id, Username: username, Password: password, Created_at: created_at, Updated_at: updated_at, AdminD: isAdmin})
	//return
}

adtempl.ExecuteTemplate(res, "read.html", ps)
}

func updateUser(res http.ResponseWriter, req *http.Request)  {
//select id's
rows, err := db.Query("SELECT id FROM new_table")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

var user = req.FormValue("ids")
var newUsername = req.FormValue("username")
var ps []PageData
id, err := strconv.Atoi(user)

for rows.Next() {
	err = rows.Scan(&id)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	ps = append(ps, PageData{Id: id})
}

stmt, err := db.Prepare("UPDATE new_table SET username=?, updated_at=? WHERE id=?")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

rs, err := stmt.Exec(newUsername,time.Now(), id)
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

affect, err := rs.RowsAffected()
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

if req.Method != "POST" {
	adtempl.ExecuteTemplate(res, "update.html", ps)
	return
}

fmt.Println("row :",affect," affected")
}

func deleteUser(res http.ResponseWriter, req *http.Request)  {
//select id's
rows, err := db.Query("SELECT id FROM new_table")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusNoContent)
	return
}

var user = req.FormValue("ids")
var ps []PageData
id, err := strconv.Atoi(user)

for rows.Next() {
	err = rows.Scan(&id)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	ps = append(ps, PageData{Id: id})
}
//
if req.Method != "POST" {
	adtempl.ExecuteTemplate(res, "delete.html", ps)
	return
}
// delete
stmt, err := db.Prepare("delete from new_table where id=?")
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

rs, err := stmt.Exec(id)
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

affect, err := rs.RowsAffected()
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}



fmt.Println("row :",affect," affected")
}

func getID(id int64) interface{}  {
return id
}

func checkErr(err error) {
if err != nil {
	log.Println(err)
}
}

i think the problem should be from line: 138-170.
it's supposed to loop through the db and get the 'is_admin' column and check the value.
if it's 1 then set the cookie to 1 else set it to 2 which means the user on that row can be redirected to user index or admin index.
The session logs into admin whether or not you're admin.
Go is looking harder by the day.
Please I need help. I know my codes are not the best of techniques but you can start from anywhere to help me even if it's about #cleancoding

Go is looking harder by the day.

You seem to be writing Go just fine. The difficulty is actually in the domain. Other than Go, you also need to know html, sql, cookies, http, etc. None of these are trivial, and their interactions make things even more difficult.

The next part of the difficulty comes from you trying to figure everything out by yourself (with some help from us). I really recommend getting something like Web Development with Go, which will help you through the basics of all these interactions. Your frustration level will be reduced because you will be getting results faster and not encountering as many problems.

i think the problem should be from line: 138-170.

This forum does not display line numbers, so they aren’t especially helpful as a reference. I think you are referring to the if isAdmin == 1 block in login.

The first problem I see with login is that you request every user from the database. Since you loop through every user, my guess is that the first user the db returns is an admin.

I expected to see something like db.QueryRow("select password, is_admin from new_table where username = ?", username)


I have to guess things to answer the questions you ask. The more you tell us about what is happening, the better we can help. To see what I mean, pretend you have never seen the code you posted and know nothing that is not in your post. Then try to answer some of these questions:

  • Does the code compile?
  • Can I run the code (to reproduce the problem)?
  • How can the problem be encountered (e.g., what actions are needed to see that it happens)
  • How can I tell the problem has occurred?
  • What should have happened instead?
  • What is the execution path through the program to get to the error?
  • Are the values set in login getting through to index
  • What values are passed through?

Since you asked a question here, I assume you don’t how to solve the problem. You already know (or at least have the possibility of finding out) what is going on in the environment where the problem exists. We don’t have the option. We only have whatever is in your post to figure out how to make the problem even exist before there is any chance of solving it.

Working through questions like the ones above are the first steps in problem solving. Another thing you can do is write very small programs to figure out very specific things (e.g., how do cookies work, how to authenticate a user, how to figure out if a user is an admin). A nice benefit of little programs is that they are easier to share and have fewer dependencies.

2 Likes

This is indeed encouraging.
Well I tried the small programs for cookies, session but never with db. Just thought I could just move all to a lil larger program.
Yes in the db, the first user is an admin.
So I see why.
Sql is prolly one of the things I should dig in.
At least my go codes aren’t so bad after all.:relieved:
I’ve been thinking of breaking the codes but sometimes don’t just know how again go wants me to code it.
Like using separate files etc.
Will work on this now and give you feedback.
Thanks @nathankerr

1 Like

Working code is good code. Basically any code can be improved, but it has to work before you can make it better.

For your purposes, multiple files in the same package is the same as putting everything in the same file. If splitting your code into multiple files helps you, then do it. If not, don’t.

1 Like

am so tired. Saw your link for the course, that’s 200+ bucks. Need to start getting jobs so I can pay for that.
meanwhile I took ya advice and it’s working just fine. But my boolean value 'isAdmin in the struct has no use.
Cos i thought why not just have one link display if true or the other displayed if false.
Like when I run it for the first time, cookie value is set at 0, so isAdmin is false therefore login shows on the page.
But when logged in, either as admin or user, cookie value is either 1 or 2, so isAdmin is true therefore logout is to be printed out but I don’t know maybe I have to rest a lil.

After I rested. Did some reformatting, I think everything is working great.
Thanks @nathankerr

1 Like

Hey @nathankerr tried to do the same thing now using gorilla, not creating the sessions for me.
Here’s my code:
`
package main

import (
"database/sql"
"fmt"
"github.com/go-sql-driver/mysql"
"github.com/gorilla/context"
"github.com/gorilla/sessions"
"golang.org/x/crypto/bcrypt"
"html/template"
"log"
"net/http"
)

var (
err   error
db    *sql.DB
templ *template.Template
adtempl *template.Template
store = sessions.NewCookieStore([]byte("something-very-secret"))
uName string
)

type PageData struct {
Title       string
IsAuth      int
Id          int
Username    string
Password    string
Description string
Created_at  mysql.NullTime
Updated_at  mysql.NullTime
}

func init() {
templ, err = templ.ParseGlob("templates/*.html")
if err != nil {
	log.Fatalln(err.Error())
}
adtempl, err = templ.ParseGlob("templates/admin/*.html")
if err != nil {
	log.Fatalln(err.Error())
}
}

func main() {
handleDbConnection()
http.HandleFunc("/", index)
http.HandleFunc("/login", login)
http.HandleFunc("/logout", logout)
http.Handle("/assets/", http.FileServer(http.Dir("."))) //serve other files in assets dir
http.Handle("/favicon.ico", http.NotFoundHandler())
fmt.Println("server running on port :8080")
http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
//http.ListenAndServe(":8080", nil)
}

func index(res http.ResponseWriter, req *http.Request) {
session, _ := store.Get(req, "session")
var isAuth int
title := "Home || cb_net sessions"

if session.Values["loggedin"] == "0" ||
	session.Values["loggedin"] == nil {
	isAuth = 0
} else if session.Values["loggedin"] == "1" {
	var pd = PageData{Title: title, Username: uName}
	err = adtempl.ExecuteTemplate(res, "index.html", pd)
	if err != nil {
		log.Fatalln(err.Error())
	}
} else if session.Values["loggedin"] == "2" {
	isAuth = 1
} else {
	isAuth = 0
}
var pd = PageData{Title: title, Username: uName, IsAuth: isAuth}
err = templ.ExecuteTemplate(res, "index.html", pd)
if err != nil {
	session.AddFlash("unable to rectify account")
	log.Fatalln(err.Error())
}
}

func handleDbConnection() {
// Create an sql.DB and check for errors
db, err = sql.Open("mysql", "root:xxx@/GoStaffManager")
if err != nil {
	panic(err.Error())
}

// Test the connection to the database
err = db.Ping()
if err != nil {
	panic(err.Error())
}
}

func login(res http.ResponseWriter, req *http.Request) {
session, _ := store.Get(req, "session")
if req.Method != "POST" {
	err = templ.ExecuteTemplate(res, "login.html", nil)
	if err != nil {
		fmt.Println("error", err)
	}
	return
}

var username = req.FormValue("username")
password := req.FormValue("password")
var pword string
var isAdmin int
// query
rows, err := db.Query("SELECT username, password FROM new_table WHERE username = ?", username)
if err != nil {
	log.Println(err)
	http.Error(res, "there was an error", http.StatusInternalServerError)
	return
}

for rows.Next() {
	err = rows.Scan(&pword, &isAdmin)
	if err != nil {
		log.Println(err)
		http.Error(res, "there was an error", http.StatusInternalServerError)
		return
	}
	if isAdmin == 1 {
		// Validate the password
		err = bcrypt.CompareHashAndPassword([]byte(pword), []byte(password))
		// If wrong password redirect to the login
		if err != nil {
			session.AddFlash("unable to rectify account")
			fmt.Println("invalid")
			http.Redirect(res, req, "/login", 301)
			return
		}
		uName = username
		session.Values["loggedin"] = "1"
		session.Save(req, res)
	} else {
		// Validate the password
		err = bcrypt.CompareHashAndPassword([]byte(pword), []byte(password))
		// If wrong password redirect to the login
		if err != nil {
			session.AddFlash("unable to rectify account")
			fmt.Println("invalid")
			http.Redirect(res, req, "/login", 301)
			return
		}
		uName = username
		session.Values["loggedin"] = "2"
		session.Save(req, res)
	}
}
http.Redirect(res, req, "/", 303)
return

}

func logout(res http.ResponseWriter, req *http.Request) {
session, _ := store.Get(req, "session")
if req.URL.Path == "/logout" {
	session.Values["loggedin"] = "0"
}
http.Redirect(res, req, "/", 302)

}

sorry for the stress, just eager to learn. When I have money, would go for the course.

Check the error returned from store.Get, it may tell you what is going on.

I didn’t check cos that’s what the gorilla/session docs advised. That gorilla would handle everything
@nathankerr

If you are referring to the comment:

Get a session. Get() always returns a session, even if empty.

from the first example from http://www.gorillatoolkit.org/pkg/sessions, you should also notice that example checks the error. The error might tell you there was a problem getting the session from the request, and still give you an empty session.

You can only be hurt by not checking errors. If the function “would handle everything” it would not return an error.

Okay @nathankerr i check the err, no err. Yet no session. Like i saw it from a tutorial by todd, tried to do mine. Oh No it isn’t working.
So here am I.

What exactly do you mean by “it isn’t working”?

Also, when GETing /, the admin/index.html template is rendered even though I had not tried to login.

That’s what am saying.
Even though I checked cookie on my browser, nothing is created.
Yet the admin/index.html is rendering.
It is supposed to render the landing page first.
Then after login.
Based on the is_admin table in db.
The auth is set.
Now based on the auth
Render the rest of it all. Just what I did with hardcoded cookie.
Why am I getting this instead

That’s what am saying.

That’s not what you said. You said it isn’t working, which means basically nothing.


So, when there shouldn’t be a session (e.g., not logged in, there is no cookie), your index handler code does the wrong thing…

This means the problem is in your code. You might want to fix it.

Also, did you know the zero value of an int is 0?

The zero value of an item retrieved from a map is the zero value of the value type for that map.

I feel like sharing what I’ve got for login/authentication might help you, so here it goes: (NOTE: I’m not using Gorilla sessions, mainly because I want to use the Standard Go approach to Context which wasn’t part of the language when Gorilla built its Context implementation within its toolkit)

package main

import (
	"html/template"
	"log"
	"net/http"

	"github.com/alexedwards/scs/session"
	"github.com/jinzhu/gorm"
)

// AuthServe middleware to handle Authentication via Session Cookies
func AuthServe(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		userID, err := session.GetInt(r, "userID")
		if err != nil {
			http.Error(w, err.Error(), http.StatusUnauthorized)
		}
		if userID > 0 {
			handler(w, r)
		} else {
			http.Redirect(w, r, "/", http.StatusUnauthorized)
		}
	}
}

// LoginHandler Handles requests for logging into Services
func LoginHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		t, _ := template.ParseFiles("Templates/contentlayout.html", "Templates/publicnav.html", "Templates/login.html")
		t.Execute(w, "Login Page!")
	case "POST":
		Db, err := gorm.Open(DATABASE, CREDENTIALS)
		defer Db.Close()
		if err != nil {
			log.Panic(err)
		}
		r.ParseForm()
		// Define Result struct for Database Query
		type Result struct {
			UserID int64
		}

		result := Result{}
		Db.Table("emails").Select("user_id").Where("email = ?", r.PostFormValue("email")).Scan(&result)

		user := User{}
		Db.Where("id = ?", uint(result.UserID)).Find(&user)
		if user.Password == r.PostFormValue("password") {
			// Check to see if user has active sessions
			err := session.PutInt(r, "userID", int(user.ID))
			//If we have an error then there is no session in the database, so we should create it
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
			http.Redirect(w, r, "/dashboard/my/", 302)
		}
	}
}

// LogoutHandler answers requests to logout, by destroying user's authToken
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
	session.Destroy(w, r)
	http.Redirect(w, r, "/", 303)

}

and my actual main.go file where I use a session memstore to handle cookie and session data:

package main

import (
	"log"
	"net/http"
	"os"

	"github.com/alexedwards/scs/engine/memstore"
	"github.com/alexedwards/scs/session"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
)

// Init opens a connection to Database and Migrates Models
func Init() {
	Db, err := gorm.Open("postgres", "user=Meliphas password=them47r1x dbname=Meliphas sslmode=disable")
	defer Db.Close()
	if err != nil {
		log.Panic(err)
	}
	Db.AutoMigrate(&User{}, &Profile{}, &Email{}, &Address{}, &Speciality{}, &Organization{}, &Membership{}, &Event{}, &Message{}, &Comment{}, &Contact{})
	return
}

// DATABASE is global environment string for type of Database
var DATABASE = "postgres"

// CREDENTIALS is global environment string for connectin to Database
var CREDENTIALS = "MY DATABASE CREDENTIALS"

// GOOGLEKEY is global environment string containing Google API key
var GOOGLEKEY = "&key=MYGOOGLEKEY"

// GEOCODEURL api url for Google Geocode requests
var GEOCODEURL = "https://maps.googleapis.com/maps/api/geocode/json?"

func main() {
	Init()
	// Session storage engine Initialization
	engine := memstore.New(0)
	sessionManager := session.Manage(engine)
	multiplex := mux.NewRouter()
	multiplex.StrictSlash(true)
	// Setup path to Public folder to serve files from file system
	multiplex.PathPrefix("/Public/").Handler(http.StripPrefix("/Public/", http.FileServer(http.Dir("Public"))))
	// Set Standard Routes
	multiplex.HandleFunc("/", WelcomeHandler)
	multiplex.HandleFunc("/directory/", DirectoryHandler)
	multiplex.HandleFunc("/dashboard/my/", AuthServe(DashboardHandler))
	multiplex.HandleFunc("/dashboard/profile/", AuthServe(ProfileHandler))
	multiplex.HandleFunc("/dashboard/organizations/", AuthServe(OrganizationHandler))
	multiplex.HandleFunc("/register/", RegisterHandler)
	multiplex.HandleFunc("/login/", LoginHandler)
	multiplex.HandleFunc("/logout/", AuthServe(LogoutHandler))

	http.ListenAndServe("127.0.0.1:8000", handlers.LoggingHandler(os.Stdout, sessionManager(multiplex)))
}

@nathankerr okay sorry for my language construct. So what are you suggesting or saying?
wow! this is so much. Don’t even know where to start from.
So you don’t use gorilla/sessions.
And with this authentication, From my post; raw hardcode cookie and session, i discovered that even without being logged in, you can still access the /create, /read etc routes via url.
just add the route after the ``localhost:8080`. So now with this form of auth, can that also be checked?
Cos You have to log in and you have to have a session cos my codes check sessions.
I will take my time later to understand this code.
Why does creating middlewares looks so strange with many abstract methods/functions.
Thanks @CurtGreen
Was this or is this like a real project you did or working on cos I’ll love to know more.

So you don’t use gorilla/sessions.

I didn’t say this. I said “the problem is in your code”.

Slow down a bit and focus on the contents of func index(res http.ResponseWriter, req *http.Request). The code in this function isn’t doing what you think it should.

Imagine you have just started the server. There are no stored sessions. No-one has logged in or out. Your browser doesn’t have any cookies set for this server.

The server receives its first request for /, index is called.

The code slowly progresses. The first line is executed and a session is returned without an error. What do you think should be in that session? Now add code to show what is actually in that session. You restart the server and request. Do the contents of session match your expectations? If so, you continue on to the next line. If not, how does the difference between what you thought session was and what it actually is affect your understanding of the function?

Line by line, you slowly and carefully verify your expectations. Every time your expectations are not met, you change the way you think and possibly the code (if what it actually does is not what needs to be done).

This is the way of the programmer. Code doesn’t do what you want it to do, it does what it says it does, exactly and precisely, and nothing more.

When the code doesn’t do what you expect (i.e., it doesn’t work), the problem in the code can be found where what you expect and what is don’t match.

As your expectations better match reality, the code you write will naturally become better.

Now, work through your code. Figure out what is actually does.

2 Likes

The code I shared is from a project that I am presently working on, it is by far not production ready as there are some security things that need to be done, such as encrypting passwords and what not. I work from a standpoint of creating the working design of the program and then refining it as I go along.

There are no abstract functions in my middleware, its a simple function that accepts a function conforming to the http handler function interface, that returns a function conforming to that same interface. We do this so that we can pass into it any chain of functions we need, by doing whats required inside its returned function and then calling the initial function that was passed into the middleware.

As far as sessions are concerned, it’s not that I don’t use them at all its that I use a different package than Gorilla Sessions, I use Alex Edwards’ session package and presently manage it with a memory store because it doesn’t matter if my users get dumped out w/o remembering the session if the server crashes.

@nathankerr Okay. I think it’s like I render the template before saving the session.
Probably. Still looking.

@CurtGreen am interested. cos I really need to know golang. So please can it be like a learning process for me?

I’m willing to help with things that you find yourself stuck on, but I don’t have the time to teach you as a class like experience. I can share with you my approach to tackling the learning process in any given language: find your problem space, examine present best practices and design patterns in that area, find implementation examples in your chosen language, try to understand whats going on read blogs and try to build simple implementations of the pattern yourself.

This will give you tons of experience debugging your own implementations, and more understanding of the bells and whistles of a full featured package implementation of what you’re trying to achieve. If you get stuck on something where google yields no results reach out for help.