package main import ( "io/ioutil" "log" "strings" "net/http" "encoding/json" "fmt" "time" "github.com/codegangsta/negroni" "github.com/dgrijalva/jwt-go" "os" ) //RSA KEYS AND INITIALISATION const ( privKeyPath = "path/to/keys/app.rsa" pubKeyPath = "path/to/keys/app.rsa.pub" ) var VerifyKey, SignKey []byte func initKeys(){ var err error SignKey, err = ioutil.ReadFile(privKeyPath) if err != nil { log.Fatal("Error reading private key") return } VerifyKey, err = ioutil.ReadFile(pubKeyPath) if err != nil { log.Fatal("Error reading public key") return } } //STRUCT DEFINITIONS type UserCredentials struct { Username string `json:"username"` Password string `json:"password"` } type User struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` Password string `json:"password"` } type Response struct { Data string `json:"data"` } type Token struct { Token string `json:"token"` } //SERVER ENTRY POINT func StartServer(){ //PUBLIC ENDPOINTS http.HandleFunc("/login", LoginHandler) //PROTECTED ENDPOINTS http.Handle("/resource/", negroni.New( negroni.HandlerFunc(ValidateTokenMiddleware), negroni.Wrap(http.HandlerFunc(ProtectedHandler)), )) log.Println("Now listening...") http.ListenAndServe(":8000", nil) } func main() { initKeys() StartServer() } ////////////////////////////////////////// /////////////ENDPOINT HANDLERS//////////// ///////////////////////////////////////// func ProtectedHandler(w http.ResponseWriter, r *http.Request){ response := Response{"Gained access to protected resource"} JsonResponse(response, w) } func LoginHandler(w http.ResponseWriter, r *http.Request) { var user UserCredentials //decode request into UserCredentials struct err := json.NewDecoder(r.Body).Decode(&user) if err != nil { w.WriteHeader(http.StatusForbidden) fmt.Fprintf(w, "Error in request") return } fmt.Println(user.Username, user.Password) //validate user credentials if strings.ToLower(user.Username) != "alexcons" { if user.Password != "kappa123" { w.WriteHeader(http.StatusForbidden) fmt.Println("Error logging in") fmt.Fprint(w, "Invalid credentials") return } } //create a rsa 256 signer signer := jwt.New(jwt.GetSigningMethod("RS256")) //set claims signer.Claims["iss"] = "admin" signer.Claims["exp"] = time.Now().Add(time.Minute * 20).Unix() signer.Claims["CustomUserInfo"] = struct { Name string Role string }{user.Username, "Member"} tokenString, err := signer.SignedString(SignKey) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintln(w, "Error while signing the token") log.Printf("Error signing token: %v\n", err) } //create a token instance using the token string response := Token{tokenString} JsonResponse(response, w) } //AUTH TOKEN VALIDATION func ValidateTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { //validate token token, err := jwt.ParseFromRequest(r, func(token *jwt.Token) (interface{}, error){ return VerifyKey, nil }) if err == nil { if token.Valid{ next(w, r) } else { w.WriteHeader(http.StatusUnauthorized) fmt.Fprint(w, "Token is not valid") } } else { w.WriteHeader(http.StatusUnauthorized) fmt.Fprint(w, "Unauthorised access to this resource") } } //HELPER FUNCTIONS func JsonResponse(response interface{}, w http.ResponseWriter) { json, err := json.Marshal(response) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") w.Write(json) }