《Web Development with Go》JWT认证满意版

Posted aguncn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Web Development with Go》JWT认证满意版相关的知识,希望对你有一定的参考价值。

这个比昨晚的要满意,

认证放到中间件那里了。

Mux使用的是gorilla,

中间件使用的是negroni,

启动是用的negroni.classic方法。

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/codegangsta/negroni"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
	"github.com/gorilla/mux"
)

// using asymmetric crypto/RSA keys
// location of the files used for signing and verification
const (
	privKeyPath = "keys/app.rsa"     // openssl genrsa -out app.rsa 1024
	pubKeyPath  = "keys/app.rsa.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
)

const (
	SecretKey = "welcome to wangshubo‘s blog"
)

// verify key and sign key
var (
	verifyKey, signKey []byte
)

//struct User for parsing login credentials
type User struct {
	UserName string `json:"username"`
	Password string `json:"password"`
}

// read the key files before starting http handlers
func init() {
	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 private key")
		return
	}
}

func authMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	// validate the token
	pubKey, err := jwt.ParseRSAPublicKeyFromPEM(verifyKey)
	if err != nil {
		fmt.Println("ParseRSAPublicKeyFromPEM:", err.Error())
		return
	}
	token, err := request.ParseFromRequest(r,
		request.AuthorizationHeaderExtractor,
		func(token *jwt.Token) (interface{}, error) {
			// since we only use one private key to sign the tokens,
			// we also only use its public counter part to verify
			return pubKey, nil
		})

	if err == nil && token.Valid {
		next(w, r)
	} else {
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprint(w, "Authentication failed")
	}
}

// reads the login credentials, checks them and creates JWT the token
func loginHandler(w http.ResponseWriter, r *http.Request) {
	var user User
	//decode into User struct
	err := json.NewDecoder(r.Body).Decode(&user)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, "Error in request body")
		return
	}
	log.Println(user.UserName, user.Password)
	// validate user credentials
	if user.UserName != "shijuvar" || user.Password != "pass" {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprintln(w, "Wrong info")
		return
	}

	// create a signer for rsa 256
	t := jwt.New(jwt.SigningMethodRS256)
	// set our claims
	claims := make(jwt.MapClaims)
	claims["iss"] = "admin"
	claims["CustomUserInfo"] = struct {
		Name string
		Role string
	}{user.UserName, "Member"}
	claims["exp"] = time.Now().Add(time.Minute * 20).Unix()
	t.Claims = claims

	priKey, err := jwt.ParseRSAPrivateKeyFromPEM(signKey)
	if err != nil {
		fmt.Println("ParseRSAPrivateKeyFromPEM:", err.Error())
		return
	}
	tokenString, err := t.SignedString(priKey)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, "Sorry, error while Signing Token!")

		log.Printf("Token Signing error: %v
", err)
		return
	}
	response := Token{tokenString}
	jsonResponse(response, w)
}

// only accessible with a valid token
func authHandler(w http.ResponseWriter, r *http.Request) {

	response := Response{"Authorized to the system"}
	jsonResponse(response, w)

}

type Response struct {
	Text string `json:"text"`
}
type Token struct {
	Token string `json:"token"`
}

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)
}

//Entry point of the program
func main() {
	r := mux.NewRouter()
	r.HandleFunc("/login", loginHandler).Methods("POST")
	r.Handle("/auth", negroni.New(
		negroni.HandlerFunc(authMiddleware),
		negroni.Wrap(http.HandlerFunc(authHandler)),
	)).Methods("POST")
	n := negroni.Classic()
	n.UseHandler(r)
	n.Run(":8080")

}

  技术图片

以上是关于《Web Development with Go》JWT认证满意版的主要内容,如果未能解决你的问题,请参考以下文章

《Web Development with Go》JWT认证满意版

在 Rails 中隐藏按钮(Agile Web Development with Rails 书)

Building RESTful Web services with Go.pdf

<Test-Driven Development with Python;学习笔记 第一部分 测试驱动开发基础

<Test-Driven Development with Python;学习笔记 第一部分 测试驱动开发基础

build-web-application-with-golang学习笔记