echo framework 에서 JWT 사용 예제 > IT 기술백서

[code]

package api

import (

  “fmt”

  “net/http”

  “os”

  “time”

  “github.com/dgrijalva/jwt-go”

  “github.com/labstack/echo”

  g “githumb.com/hyuk-june/petoo_back_end/app/globals”

  “githumb.com/hyuk-june/petoo_back_end/app/models”

)

type AuthApi struct {

}

// Login 성공하면 access 토큰과 refresh 토큰을 출력한다

func (a *AuthApi) Login(c echo.Context) error {

  email := c.FormValue(“email”)

  password := c.FormValue(“password”)

  lu := &models.LoginUser{

    Email:    email,

    Password: password,

  }

  // Validate

  if err := c.Validate(lu); err != nil {

    return c.JSON(http.StatusBadRequest, err.Error())

  }

  // database 로부터 해당 사용자정보를 불러온다

  user := new(models.User)

  if err := g.DB.First(user, “email=?”, email).Error; err != nil {

    return echo.ErrUnauthorized

  }

  // 비밀번호를 검증한다

  if err := models.VerifyPassword(user.Password, password); err != nil {

    fmt.Println(err)

    fmt.Println(err.Error())

    return echo.ErrUnauthorized

  }

  // claims(데이터) 생성

  claims := map[string]interface{}{

    “sub”:   os.Getenv(“API_TOKEN_SUB”),

    “id”:    user.ID,

    “email”: user.Email,

  }

  // access, refresh 토큰 생성

  accessToken, refreshToken, err := a.generateToken(c, claims)

  if err != nil {

    return err

  }

  // 출력

  return c.JSON(http.StatusOK, map[string]string{

    “access_token”:  accessToken,

    “refresh_token”: refreshToken,

  })

}

// RefreshToken 토큰갱신: 성공하면 access 토큰과 refresh 토큰을 모두 다시 출력한다.

func (a *AuthApi) RefreshToken(c echo.Context) error {

  refreshToken := c.FormValue(“refresh_token”)

  // 토큰을 분석하고 유효한지 검증하고 *jwt.Token 객체로 반환한다.

  // KeyFunc 은 sceret key를 반환해야 한다.

  token, err := jwt.Parse(refreshToken, func(token *jwt.Token) (interface{}, error) {

    // 클라이언트로 받은 토큰이 HMAC 알고리즘이 맞는지 확인

    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {

      return nil, fmt.Errorf(“Unexpected signing method: %v”, token.Header[“alg”])

    }

    return []byte(os.Getenv(“API_SECRET”)), nil

  })

  if err != nil {

    return err

  }

  // Claims 생성

  claims, ok := token.Claims.(jwt.MapClaims)

  if !ok || !token.Valid {

    return echo.ErrInternalServerError

  }

  // 발급할때의 토큰제목과 일치하는지 체크

  if claims[“sub”].(string) != os.Getenv(“API_TOKEN_SUB”) {

    return echo.ErrBadRequest

  }

  // 재발급

  cl := map[string]interface{}(claims)

  accessToken, refreshToken, err := a.generateToken(c, cl)

  if err != nil {

    return err

  }

  // 출력

  return c.JSON(http.StatusOK, map[string]string{

    “access_token”:  accessToken,

    “refresh_token”: refreshToken,

  })

}

// generateToken access 토큰과 refresh 토큰을 쌍으로 반환한다

func (a *AuthApi) generateToken(c echo.Context, claimsMap map[string]interface{}) (string, string, error) {

  // access 토큰 생성: 유효기간 20분

  accessToken, err := a.createToken(

    c,

    claimsMap,

    time.Now().Add(time.Minute*20),

    “access_token”,

  )

  if err != nil {

    return “”, “”, err

  }

  // refresh 토큰 생성: 유효기간 24시간

  refreshToken, err := a.createToken(

    c,

    claimsMap,

    time.Now().Add(time.Hour*24),

    “refresh_token”,

  )

  if err != nil {

    return “”, “”, err

  }

  return accessToken, refreshToken, nil

}

// 단위 토큰 만들기

func (a *AuthApi) createToken(c echo.Context, data map[string]interface{}, expire time.Time, cookieName string) (string, error) {

  // token

  token := jwt.New(jwt.SigningMethodHS256)

  claims := token.Claims.(jwt.MapClaims)

  for key, val := range data {

    claims[key] = val

  }

  claims[“exp”] = expire.Unix()

  encToken, err := token.SignedString([]byte(os.Getenv(“API_SECRET”)))

  if err != nil {

    return “”, err

  }

  // 쿠키 (클라이언트가 따로 저장하는 수고를 덜기 위해서…) – Option

  if cookieName != “” {

    cookie := new(http.Cookie)

    cookie.Name = cookieName

    cookie.Value = encToken

    cookie.Expires = expire

    c.SetCookie(cookie)

  }

  return encToken, nil

}

[/code]

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤