|
@@ -1,8 +1,8 @@
|
|
|
package main
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
"net/http"
|
|
|
- "time"
|
|
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
"github.com/labstack/echo"
|
|
@@ -18,31 +18,61 @@ func (h *handler) login(c echo.Context) error {
|
|
|
|
|
|
// Check in your db if the user exists or not
|
|
|
if username == "jon" && password == "password" {
|
|
|
- // Create token
|
|
|
- token := jwt.New(jwt.SigningMethodHS256)
|
|
|
-
|
|
|
- // Set claims
|
|
|
- // This is the information which frontend can use
|
|
|
- // The backend can also decode the token and get admin etc.
|
|
|
- claims := token.Claims.(jwt.MapClaims)
|
|
|
- claims["name"] = "Jon Doe"
|
|
|
- claims["admin"] = true
|
|
|
- claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
|
|
|
-
|
|
|
- // Generate encoded token and send it as response.
|
|
|
- // The signing string should be secret (a generated UUID works too)
|
|
|
- t, err := token.SignedString([]byte("secret"))
|
|
|
+ tokens, err := generateTokenPair()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- return c.JSON(http.StatusOK, map[string]string{
|
|
|
- "token": t,
|
|
|
- })
|
|
|
+
|
|
|
+ return c.JSON(http.StatusOK, tokens)
|
|
|
}
|
|
|
|
|
|
return echo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
+// This is the api to refresh tokens
|
|
|
+// Most of the code is taken from the jwt-go package's sample codes
|
|
|
+// https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac
|
|
|
+func (h *handler) token(c echo.Context) error {
|
|
|
+ type tokenReqBody struct {
|
|
|
+ RefreshToken string `json:"refresh_token"`
|
|
|
+ }
|
|
|
+ tokenReq := tokenReqBody{}
|
|
|
+ c.Bind(&tokenReq)
|
|
|
+
|
|
|
+ // Parse takes the token string and a function for looking up the key.
|
|
|
+ // The latter is especially useful if you use multiple keys for your application.
|
|
|
+ // The standard is to use 'kid' in the head of the token to identify
|
|
|
+ // which key to use, but the parsed token (head and claims) is provided
|
|
|
+ // to the callback, providing flexibility.
|
|
|
+ token, err := jwt.Parse(tokenReq.RefreshToken, func(token *jwt.Token) (interface{}, error) {
|
|
|
+ // Don't forget to validate the alg is what you expect:
|
|
|
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
|
+ return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
|
+ }
|
|
|
+
|
|
|
+ // hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
|
|
+ return []byte("secret"), nil
|
|
|
+ })
|
|
|
+
|
|
|
+ if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
|
+ // Get the user record from database or
|
|
|
+ // run through your business logic to verify if the user can log in
|
|
|
+ if int(claims["sub"].(float64)) == 1 {
|
|
|
+
|
|
|
+ newTokenPair, err := generateTokenPair()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.JSON(http.StatusOK, newTokenPair)
|
|
|
+ }
|
|
|
+
|
|
|
+ return echo.ErrUnauthorized
|
|
|
+ }
|
|
|
+
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
// Most of the code is taken from the echo guide
|
|
|
// https://echo.labstack.com/cookbook/jwt
|
|
|
func (h *handler) private(c echo.Context) error {
|