Rewriting http HandlerFunc to gin HandlerFunc - go

I have a middleware written with httpHandler but now I am trying to use gin-gornic and needed to provide an alternative. I have tried rewriting but still not working as I want it to work.
func AuthMiddlewarex(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth == "" {
h.ServeHTTP(w, r)
return
}
bearer := "Bearer "
auth = auth[len(bearer):]
validate, err := utils.JwtValidate(context.Background(), auth)
if err != nil || !validate.Valid {
http.Error(w, "Invalid token", http.StatusForbidden)
return
}
customClaim, _ := validate.Claims.(*utils.JwtCustomClaim)
ctx := context.WithValue(r.Context(), authString("auth"), customClaim)
r = r.WithContext(ctx)
h.ServeHTTP(w, r)
})
}
After rewriting it, I am left with this.
func AuthMiddlewareq() gin.HandlerFunc {
return func(c *gin.Context) {
auth := c.Request.Header.Get("Authorization")
if auth == "" {
c.Next()
// next.ServeHTTP(w, r)
return
}
bearer := "Bearer "
auth = auth[len(bearer):]
validate, err := utils.JwtValidate(context.Background(), auth)
if err != nil || !validate.Valid {
http.Error(c.Writer, "Invalid token", http.StatusForbidden)
// http.Error(w, "Invalid token", http.StatusForbidden)
return
}
customClaim, _ := validate.Claims.(*utils.JwtCustomClaim)
ctx := context.WithValue(c.Request.Context(), authString("auth"), customClaim)
c.Request = c.Request.WithContext(ctx)
c.Next()
// next.ServeHTTP(w, r)
}
}

Related

Golang - Google OAuth 2 authorization - Error: redirect_uri_mismatch

I did all of this: Google OAuth 2 authorization - Error: redirect_uri_mismatch
I have added auth Uri's, but still doesn't work
"redirect_uris":["https://localhost:8080","http://localhost:8080","http://localhost:8080/google_login","http://localhost:8080/google_callback","https://localhost","http://localhost"]
But Im still getting this error message:
My main.go:
func main() {
// load configs
godotenv.Load(".env")
config.SetupConfig()
// create a router
mux := http.NewServeMux()
// define routes
mux.HandleFunc("/google_login", controllers.GoogleLogin)
mux.HandleFunc("/google_callback", controllers.GoogleCallback)
// run server
log.Println("started server on :: http://localhost:8080/")
if oops := http.ListenAndServe(":8080", mux); oops != nil {
log.Fatal(oops)
}
}
contants.go:
func SetupConfig() *oauth2.Config {
conf := &oauth2.Config{
ClientID: os.Getenv("NoteClientId"),
ClientSecret: os.Getenv("NoteClientSecret"),
RedirectURL: "http://localhost:8080/google/callback",
Scopes: []string{
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
},
Endpoint: google.Endpoint,
}
return conf
}
google.go:
func GoogleLogin(res http.ResponseWriter, req *http.Request) {
googleConfig := config.SetupConfig()
url := googleConfig.AuthCodeURL("randomstate")
http.Redirect(res, req, url, http.StatusSeeOther)
}
func GoogleCallback(res http.ResponseWriter, req *http.Request) {
state := req.URL.Query()["state"][0]
if state != "randomstate" {
fmt.Fprintln(res, "states dont match")
return
}
code := req.URL.Query()["code"][0]
googleConfig := config.SetupConfig()
token, err := googleConfig.Exchange(context.Background(), code)
if err != nil {
fmt.Fprintln(res, "Code-Token Exchange failed")
}
resp, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
if err != nil {
fmt.Fprintln(res, "User data fetch failed")
}
userData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Fprintln(res, "Json Parsing Failed")
}
fmt.Fprintln(res, string(userData))
}
None of these URIs
["https://localhost:8080","http://localhost:8080","http://localhost:8080/google_login","http://localhost:8080/google_callback","https://localhost","http://localhost"]
march the redirect URI you have configured in constants.go
RedirectURL: "http://localhost:8080/google/callback",
Change one or the other so that they match

Gorm and go-chi REST patch resource

I am building a REST API using chi and gorm
I want to have a patch route where I can update only the properties I receive in the request body.
I am not sure how is the best way of passing there properties to gorm update method.
Which would be a good way of doing so?
Here is the handler method.
func (m Env) UpdateHandler(w http.ResponseWriter, r *http.Request) {
var delta InsurancePolicy
insurancePolicy := r.Context().Value("insurancePolicy").(InsurancePolicy)
err := json.NewDecoder(r.Body).Decode(&delta)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
result := m.DB.Model(&insurancePolicy).Update(delta)
if result.Error != nil {
w.WriteHeader(http.StatusInternalServerError)
} else {
err := json.NewEncoder(w).Encode(insurancePolicy)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
It uses this middleware to preload the request:
func (m Env) InsurancePolicyCtx(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var insurancePolicy InsurancePolicy
result := m.DB.First(&insurancePolicy, chi.URLParam(r, "id"))
if result.Error != nil {
w.WriteHeader(http.StatusNotFound)
return
}
ctx := context.WithValue(r.Context(), "insurancePolicy", insurancePolicy)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

How to write user login error in login page

I'm new one for Golang programming. In Golang how to display the username error.
This is my code:
func LoginHandler(w http.ResponseWriter, req *http.Request){
if req.Method == http.MethodPost{
un := req.FormValue("username")
p := req.FormValue("password")
u, ok := dbUsers[un]
if !ok{
var body, _ = helpers.LoadFile("sss/login.html")
fmt.Fprintf(response, body)
//fmt.Fprintln(w, "incorrect user name")
//return
}
if u.Password != p{
fmt.Fprintln(w, "incorrect password")
return
}
http.Redirect(w, req, "/index.html", http.StatusSeeOther)
return
}
}
In go You have different ways for error handling
func SomeHandler(w http.ResponseWriter, r *http.Request) (int, error) {
if req.Method == http.MethodPost{
un := req.FormValue("username")
p := req.FormValue("password")
u, ok := dbUsers[un]
if !ok{
var body, _ = helpers.LoadFile("sss/login.html")
return 400, errors.New("can't load sss/login")
}
if u.Password != p{
return 400, errors.New("wrong password")
}
http.Redirect(w, req, "/index.html", http.StatusSeeOther)
return 302, nil
}
or
func SomeHandler(w http.ResponseWriter, r *http.Request) {
un := req.FormValue("username")
p := req.FormValue("password")
u, ok := dbUsers[un]
if !ok{
var body, _ = helpers.LoadFile("sss/login.html")
http.Error(w, "can't load sss/login", 400)
return
}
if u.Password != p{
http.Error(w, "wrong password", 400)
return
}
http.Redirect(w, req, "/index.html", http.StatusSeeOther)
return
}
For more information You can read here very helpful blogpost about middlewares:
https://www.nicolasmerouze.com/middlewares-golang-best-practices-examples/
Post with simple example:
https://blog.questionable.services/article/http-handler-error-handling-revisited/
Http package docs: https://golang.org/pkg/net/http/
You could do something a little bit more elegant.
Pass a context object to the template and render the error there.
func index(w http.ResponseWriter, r *http.Request) {
context := make(map[string]string]
context["Error"] = "Username error"
t := template.Must(template.ParseFiles("./templates/index.html"))
t.Execute(w, context)
}
Then, on the template render it like this
{{.Error}}}
If no error occurred, the field will be empty.
Cheers.

Cannot get gorilla session.Value by key

The problem is, cannot get value from session.Value in another file in the same package
In the controllers.go file
func (c *AuthenticationControllers) AdminLogin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
//AUTHENTICATION
if answer {
w.Write([]byte("Successful Authenticated!"))
//1* Create Session
session, _ := store.Get(r, "session") //SESSION START
///Here I've setted true
session.Values["authenticated"] = true//Successful Authenticated
sessionToken, _ := uuid.NewV4() //Generate session token
session.Values["userid"] = sessionToken.String()
session.Save(r, w)
//Redirect
http.Redirect(w, r, "/admin/application", 302)
} else {
//http.Redirect(w, r, "/login", 302)
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}
}
}
IN middleware.go file in the same package
func (m *AuthenticationMiddleWares) RequiresLogin(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session") //!!!
if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
handler(w, r)
}
}
session.Values["authenticated"] //has nil value, but has to be true after authentification in order to get you access to the route
router.HandleFunc("/admin/applications", authMiddle.RequiresLogin(authContrl.Application()))
What I have done wrong? Why session.Values["authenticated"] returns "nil"
session, _ := store.Get(r, "session") //SESSION START, your session depends on the request r, which is a pointer that is created by the package that calls your controller. If you are calling session from another file, you need to ensure, that it is the same request that is passed into store.Get(). That could be the reason.

How to do error http error handling in Go language

I am little confused on how error handling should be done in go. I have read so many posts about it but still am not able to apply them on my structure of code. I am new to go so please help.
There is a main function which handles two apis: api1 and api2
func main() {
http.HandleFunc("/offers", api1)
http.HandleFunc("/getOffersList", api2)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func api1(w http.ResponseWriter, req *http.Request) {
validateRequestHeader(w, req, "GET")
// code here....
}
func api2(w http.ResponseWriter, req *http.Request) {
validateRequestHeader(w, req, "POST")
//code here....
}
func validateRequestHeader(w http.ResponseWriter, req *http.Request, allowedMethod string) {
// allow cross domain AJAX requests
w.Header().Set("Content-Type", "application/json")
if origin := req.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers",
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
// Stop here if its Preflighted OPTIONS request
if req.Method == "OPTIONS" {
return
}
if req.Method != allowedMethod {
response := "Only " + allowedMethod + " requests are allowed"
http.Error(w, response, http.StatusMethodNotAllowed)
return
}
}
In both api1 and api2 , function validateRequestHeader is getting called. If this gets true, then in the api1/api2 further code is getting executed which I do not want. How it should be handled?
if req.Method != allowedMethod {
response := "Only " + allowedMethod + " requests are allowed"
http.Error(w, response, http.StatusMethodNotAllowed)
return
}
This blog post goes into some details on how to chain multiple handler functions, which is what you should be doing. That way, you can have a validation handler, a logging handler, an authorization handler, etc etc. and just chain them together.
Essentially
func validator(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
if isRequestValid(req) {
// a valid request is passed on to next handler
next.ServeHTTP(w, req)
} else {
// otherwise, respond with an error
http.Error(w, "Bad request - Go away!", 400)
}
}
return http.HandlerFunc(fn)
}
func api1() http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
// api 1 code
}
return http.HandlerFunc(fn)
}
func api2() http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
// api 2 code
}
return http.HandlerFunc(fn)
}
And then chain them up in your main function.
func main() {
http.Handler("/offers", validate(api1()))
http.Handler("/getOffersList", validate(api2()))
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

Resources