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

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.

The first request from a user will always have an empty session. You need to correctly handle this case before worrying about saving sessions.

I don’t know @nathanerr i even commented out the first if in index so i could just deal with templ alone. Just can explain how on earth it still render templates/admin/index.html.
I don’t know.

@CurtGreen thanks.

Randomly commenting out parts of your code won’t help you understand it.

If you follow the process I described, you will know what your code does and why it does it.

Put log.SetFlags(log.Lshortfile) at the beginning of main and then use log.Println or log.Printf to examine the value of every variable and see which branches of the if statements are followed.

okay did that @nathankerr , printed out an empty map. That’s no session created so none stored. I don’t know why. But maybe This is not the best way to do it.

The first time someone goes to the site, the session should be empty. How could they have a session if they were never there before?

@nathankerr i understand what you’re saying but don’t just know how to implement it.

What exactly don’t you know how to implement?

this whole authentication process with go.

What is the very first step of that process?

first get the inputs
then do checks
if checks all = true
create a session/cookie either in client/server side
save for that particular entity for a particular period of time
then other things…

What are the inputs?