mirror of https://github.com/jlelse/GoBlog
Make authentication and captcha more secure
This commit is contained in:
parent
79a9ce6126
commit
0c52f90268
|
@ -16,22 +16,32 @@ func checkCredentials(username, password string) bool {
|
||||||
return username == appConfig.User.Nick && password == appConfig.User.Password
|
return username == appConfig.User.Nick && password == appConfig.User.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkUsername(username string) bool {
|
||||||
|
return username == appConfig.User.Nick
|
||||||
|
}
|
||||||
|
|
||||||
func jwtKey() []byte {
|
func jwtKey() []byte {
|
||||||
return []byte(appConfig.Server.JWTSecret)
|
return []byte(appConfig.Server.JWTSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func authMiddleware(next http.Handler) http.Handler {
|
func authMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// 1. Check JWT
|
// 1. Check BasicAuth
|
||||||
|
if username, password, ok := r.BasicAuth(); ok && checkCredentials(username, password) {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 2. Check JWT
|
||||||
if tokenCookie, err := r.Cookie("token"); err == nil {
|
if tokenCookie, err := r.Cookie("token"); err == nil {
|
||||||
if tkn, err := jwt.Parse(tokenCookie.Value, func(t *jwt.Token) (interface{}, error) {
|
claims := &authClaims{}
|
||||||
|
if tkn, err := jwt.ParseWithClaims(tokenCookie.Value, claims, func(t *jwt.Token) (interface{}, error) {
|
||||||
return jwtKey(), nil
|
return jwtKey(), nil
|
||||||
}); err == nil && tkn.Valid {
|
}); err == nil && tkn.Valid && claims.TokenType == "login" && checkUsername(claims.Username) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. Show login form
|
// 3. Show login form
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
h, _ := json.Marshal(r.Header.Clone())
|
h, _ := json.Marshal(r.Header.Clone())
|
||||||
b, _ := ioutil.ReadAll(io.LimitReader(r.Body, 2000000)) // Only allow 20 Megabyte
|
b, _ := ioutil.ReadAll(io.LimitReader(r.Body, 2000000)) // Only allow 20 Megabyte
|
||||||
|
@ -75,7 +85,7 @@ func checkLogin(w http.ResponseWriter, r *http.Request) bool {
|
||||||
}
|
}
|
||||||
// Check credential
|
// Check credential
|
||||||
if checkCredentials(r.FormValue("username"), r.FormValue("password")) {
|
if checkCredentials(r.FormValue("username"), r.FormValue("password")) {
|
||||||
tokenCookie, err := createTokenCookie()
|
tokenCookie, err := createTokenCookie(r.FormValue("username"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
return true
|
return true
|
||||||
|
@ -92,9 +102,19 @@ func checkLogin(w http.ResponseWriter, r *http.Request) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTokenCookie() (*http.Cookie, error) {
|
type authClaims struct {
|
||||||
|
*jwt.StandardClaims
|
||||||
|
TokenType string
|
||||||
|
Username string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTokenCookie(username string) (*http.Cookie, error) {
|
||||||
expiration := time.Now().Add(7 * 24 * time.Hour)
|
expiration := time.Now().Add(7 * 24 * time.Hour)
|
||||||
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.StandardClaims{ExpiresAt: expiration.Unix()}).SignedString(jwtKey())
|
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodHS256, &authClaims{
|
||||||
|
&jwt.StandardClaims{ExpiresAt: expiration.Unix()},
|
||||||
|
"login",
|
||||||
|
username,
|
||||||
|
}).SignedString(jwtKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
15
captcha.go
15
captcha.go
|
@ -19,10 +19,11 @@ func initCaptcha() {
|
||||||
func captchaMiddleware(next http.Handler) http.Handler {
|
func captchaMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// 1. Check JWT
|
// 1. Check JWT
|
||||||
|
claims := &captchaClaims{}
|
||||||
if captchaCookie, err := r.Cookie("captcha"); err == nil {
|
if captchaCookie, err := r.Cookie("captcha"); err == nil {
|
||||||
if tkn, err := jwt.Parse(captchaCookie.Value, func(t *jwt.Token) (interface{}, error) {
|
if tkn, err := jwt.ParseWithClaims(captchaCookie.Value, claims, func(t *jwt.Token) (interface{}, error) {
|
||||||
return jwtKey(), nil
|
return jwtKey(), nil
|
||||||
}); err == nil && tkn.Valid {
|
}); err == nil && tkn.Valid && claims.TokenType == "captcha" {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -90,9 +91,17 @@ func checkCaptcha(w http.ResponseWriter, r *http.Request) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type captchaClaims struct {
|
||||||
|
*jwt.StandardClaims
|
||||||
|
TokenType string
|
||||||
|
}
|
||||||
|
|
||||||
func createCaptchaCookie() (*http.Cookie, error) {
|
func createCaptchaCookie() (*http.Cookie, error) {
|
||||||
expiration := time.Now().Add(24 * time.Hour)
|
expiration := time.Now().Add(24 * time.Hour)
|
||||||
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.StandardClaims{ExpiresAt: expiration.Unix()}).SignedString(jwtKey())
|
tokenString, err := jwt.NewWithClaims(jwt.SigningMethodHS256, &captchaClaims{
|
||||||
|
&jwt.StandardClaims{ExpiresAt: expiration.Unix()},
|
||||||
|
"captcha",
|
||||||
|
}).SignedString(jwtKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue