Write DTO token
Create dto to transfer our token, create file token.go
save it in entities/DTO
package dto
type TokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
Create handler
create main_handler.go
and save it in interface/http/handler
and write code below.
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
"shellrean.com/auth/domain"
"shellrean.com/auth/entities/DTO"
)
type UserHandler struct {
userUsecase domain.UserUsecase
}
func NewUserHandler(r *gin.Engine, m domain.UserUsecase) {
handler := &UserHandler{
userUsecase: m,
}
r.POST("/auth", handler.Autheticate)
r.POST("/refresh-token", handler.RefreshToken)
}
We declare 2 routes, /auth will handle for authentication and /refresh-token for give user refresh token, at the same file main_handler.go add handler Authenticate
func (h *UserHandler) Autheticate(c *gin.Context) {
var u domain.User
if err := c.ShouldBindJSON(&u); err != nil {
c.JSON(
http.StatusUnprocessableEntity,
gin.H{"error": "Unprocessable Entity"},
)
return
}
res, err := h.userUsecase.Authentication(c, user)
if err != nil {
c.JSON(
http.StatusInternalServerError,
gin.H{"error": err}
)
return
}
c.JSON(http.StatusOK, gin.H{"data": res})
}
We also create handler for handle Refresh token request.
func (h *UserHandler) RefreshToken(c *gin.Context) {
var u dto.TokenResponse
if err := c.ShouldBindJSON(&u); err != nil {
c.JSON(
http.StatusUnprocessableEntity,
gin.H{"error": "Unprocessable Entity"},
)
return
}
token := domain.Token {
AccessToken: u.AccessToken,
RefreshToken: u.RefreshToken,
}
err := h.userUsecase.RefreshToken(c, &token)
if err != nil {
c.JSON(
http.StatusInternalServerError,
gin.H{"error": err}
)
return
}
data := dto.TokenResponse{
token.AccessToken,
token.RefreshToken,
}
c.JSON(http.StatusOK, gin.H{"data": data})
}
Create usecase
package usecase
import (
"context"
"time"
"fmt"
"golang.org/x/crypto/bcrypt"
"shellrean.com/auth/domain"
"shellrean.com/auth/config"
"shellrean.com/auth/entities/helper"
)
type userUsecase struct {
userRepo domain.UserRepository
contextTimeout time.Duration
}
func NewUserUsecase(d domain.UserRepository, timeout time.Duration) domain.UserUsecase {
return &userUsecase {
userRepo: d,
contextTimeout: timeout,
}
}
func (u *userUsecase) Authentication(c context.Context, ur domain.User) (td domain.Token, err error) {
ctx, cancel := context.WithTimeout(c, u.contextTimeout)
defer cancel()
user, err := u.userRepo.GetByEmail(ctx, ur.Email)
if err != nil {
return domain.Token{}, err
}
if user == (domain.User{}) {
return domain.Token{}, fmt.Errorf("Error user not found")
}
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(ur.Password))
if err != nil {
return domain.Token{}, fmt.Errorf("Invalid credential")
}
helper.GenerateTokenDetail(&td)
err = helper.CreateAccessToken(u.cfg.JWTAccessKey, user, &td)
if err != nil {
return domain.Token{}, err
}
err = helper.CreateRefreshToken(u.cfg.JWTRefreshKey, user, &td)
if err != nil {
return domain.Token{}, err
}
return
}
func (u *userUsecase) RefreshToken(c context.Context, td *domain.Token) (err error) {
ctx, cancel := context.WithTimeout(c, u.contextTimeout)
defer cancel()
token, errs := helper.VerifyToken(u.cfg.JWTRefreshKey, td.RefreshToken)
if errs != nil {
return fmt.Errorf("Invalid when verification")
}
err = helper.TokenValid(token)
if err != nil {
return fmt.Errorf("Session invalid")
}
data := helper.ExtractTokenMetadata(token)
user := domain.User{
ID: int64(data["user_id"].(float64)),
}
helper.GenerateTokenDetail(td)
err = helper.CreateAccessToken(u.cfg.JWTAccessKey, user, td)
if err != nil {
return err
}
err = helper.CreateRefreshToken(u.cfg.JWTRefreshKey, user, td)
if err != nil {
return err
}
return
}
And the last, we create main.go store it int app/main.go
Top comments (1)
terimakasih bang