Skip to content

Commit

Permalink
demo: auth (#27)
Browse files Browse the repository at this point in the history
* demo: auth

* rename

* rename
  • Loading branch information
hwbrzzl authored Sep 11, 2024
1 parent f4a8f06 commit 7169d36
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 2 deletions.
70 changes: 70 additions & 0 deletions app/http/controllers/auth_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package controllers

import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"

"goravel/app/models"
)

type AuthController struct {
// Dependent services
}

func NewAuthController() *AuthController {
return &AuthController{
// Inject services
}
}

func (r *AuthController) Login(ctx http.Context) http.Response {
// Create a user
var user models.User
if err := facades.Orm().Query().FirstOrCreate(&user, models.User{
Name: ctx.Request().Input("name", "Goravel"),
}); err != nil {
return ctx.Response().Json(http.StatusInternalServerError, http.Json{
"error": err.Error(),
})
}

var (
token string
err error
)

// Use different guards to login
if guard := ctx.Request().Header("Guard"); guard == "" {
token, err = facades.Auth(ctx).LoginUsingID(user.ID)
if err != nil {
return ctx.Response().String(http.StatusInternalServerError, err.Error())
}
} else {
token, err = facades.Auth(ctx).Guard(guard).Login(user)
if err != nil {
return ctx.Response().String(http.StatusInternalServerError, err.Error())
}
}

return ctx.Response().Header("Authorization", "Bearer "+token).Success().Json(http.Json{
"user": user,
})
}

func (r *AuthController) Info(ctx http.Context) http.Response {
var user models.User

if guard := ctx.Request().Header("Guard"); guard == "" {
if err := facades.Auth(ctx).User(&user); err != nil {
return ctx.Response().String(http.StatusInternalServerError, err.Error())
}
} else {
if err := facades.Auth(ctx).Guard(guard).User(&user); err != nil {
return ctx.Response().String(http.StatusInternalServerError, err.Error())
}
}

return ctx.Response().Success().Json(http.Json{
"user": user,
})
}
54 changes: 54 additions & 0 deletions app/http/middleware/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package middleware

import (
"errors"

"github.com/goravel/framework/auth"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
)

func Auth() http.Middleware {
return func(ctx http.Context) {
guard := facades.Config().GetString("auth.defaults.guard")
if ctx.Request().Header("Guard") != "" {
guard = ctx.Request().Header("Guard")
}

token := ctx.Request().Header("Authorization", "")
if token == "" {
ctx.Request().AbortWithStatus(http.StatusUnauthorized)
return
}

if _, err := facades.Auth(ctx).Guard(guard).Parse(token); err != nil {
if errors.Is(err, auth.ErrorTokenExpired) {
// Refresh token
token, err = facades.Auth(ctx).Guard(guard).Refresh()
if err != nil {
// Refresh time exceeded
ctx.Request().AbortWithStatus(http.StatusUnauthorized)
return
}

token = "Bearer " + token
} else {
// Token is invalid
ctx.Request().AbortWithStatus(http.StatusUnauthorized)
return
}
}

// You can get User in DB and set it to ctx

//var user models.User
//if err := facades.Auth().User(ctx, &user); err != nil {
// ctx.Request().AbortWithStatus(http.StatusUnauthorized)
// return
//}
//ctx.WithValue("user", user)

ctx.Response().Header("Authorization", token)
ctx.Request().Next()
}
}
1 change: 1 addition & 0 deletions app/providers/route_service_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (receiver *RouteServiceProvider) Boot(app foundation.Application) {

// Add routes
routes.Web()
routes.Api()
}

func (receiver *RouteServiceProvider) configureRateLimiting() {
Expand Down
3 changes: 3 additions & 0 deletions config/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func init() {
"user": map[string]any{
"driver": "jwt",
},
"admin": map[string]any{
"driver": "jwt",
},
},
})
}
14 changes: 14 additions & 0 deletions routes/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package routes

import (
"github.com/goravel/framework/facades"

"goravel/app/http/controllers"
"goravel/app/http/middleware"
)

func Api() {
authController := controllers.NewAuthController()
facades.Route().Post("auth/login", authController.Login)
facades.Route().Middleware(middleware.Auth()).Get("auth/info", authController.Info)
}
61 changes: 59 additions & 2 deletions tests/feature/route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
"github.com/stretchr/testify/suite"

"goravel/app/models"
"goravel/tests"
goraveltests "goravel/tests"
)

type RouteTestSuite struct {
suite.Suite
tests.TestCase
goraveltests.TestCase
http *resty.Client
}

Expand All @@ -39,6 +39,63 @@ func (s *RouteTestSuite) SetupTest() {
func (s *RouteTestSuite) TearDownTest() {
}

func (s *RouteTestSuite) TestAuth() {
type Response struct {
User models.User
}

tests := []struct {
name string
guard string
}{
{
name: "default guard",
},
{
name: "admin guard",
guard: "admin",
},
}

for _, test := range tests {
s.Run(test.name, func() {
// Unauthorized
resp, err := s.http.R().Get("auth/info")

s.Require().NoError(err)
s.Require().Equal(http.StatusUnauthorized, resp.StatusCode())

// Login
var authLogin Response
resp, err = s.http.R().SetResult(&authLogin).
SetHeader("Guard", test.guard).
SetBody(map[string]string{
"name": test.name,
}).Post("auth/login")

s.Require().NoError(err)
s.Require().Equal(http.StatusOK, resp.StatusCode())
s.True(authLogin.User.ID > 0)
s.Equal(test.name, authLogin.User.Name)

token := resp.Header().Get("Authorization")
s.Require().NotEmpty(token)

// Get User
var authUser Response
resp, err = s.http.R().SetResult(&authUser).SetHeaders(map[string]string{
"Authorization": token,
"Guard": test.guard,
}).Get("auth/info")

s.Require().NoError(err)
s.Require().Equal(http.StatusOK, resp.StatusCode())
s.Equal(authLogin.User.ID, authUser.User.ID)
s.Equal(authLogin.User.Name, authUser.User.Name)
})
}
}

func (s *RouteTestSuite) TestLang() {
tests := []struct {
name string
Expand Down

0 comments on commit 7169d36

Please sign in to comment.