cleanup and addes auth.signup event
This commit is contained in:
parent
2e732a8c79
commit
9e389f1d28
10 changed files with 113 additions and 79 deletions
|
@ -15,5 +15,5 @@ import (
|
|||
|
||||
// Register your events here.
|
||||
func RegisterEvents() {
|
||||
event.Subscribe("foo.bar", events.HandleFooEvent)
|
||||
event.Subscribe("auth.signup", events.HandleUserSignup)
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package events
|
||||
|
||||
import "context"
|
||||
|
||||
// Event handlers
|
||||
func HandleFooEvent(ctx context.Context, event any) {}
|
16
bootstrap/app/events/user_signup_event.go
Normal file
16
bootstrap/app/events/user_signup_event.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"AABBCCDD/plugins/auth"
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Event handlers
|
||||
func HandleUserSignup(ctx context.Context, event any) {
|
||||
userWithToken, ok := event.(auth.UserWithVerificationToken)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Printf("user signup: %v\n", userWithToken)
|
||||
}
|
|
@ -22,9 +22,16 @@ func InitializeMiddleware(router *chi.Mux) {
|
|||
|
||||
// Define your routes in here
|
||||
func InitializeRoutes(router *chi.Mux) {
|
||||
// Authentication plugin:
|
||||
// Authentication plugin
|
||||
//
|
||||
// By default the auth plugin is active. To disable the auth plugin
|
||||
// you will need to pass your own handler in the `AuthFunc`` field
|
||||
// of the `kit.AuthenticationConfig`.
|
||||
// authConfig := kit.AuthenticationConfig{
|
||||
// AuthFunc: YourAuthHandler,
|
||||
// RedirectURL: "/login",
|
||||
// }
|
||||
auth.InitializeRoutes(router)
|
||||
|
||||
authConfig := kit.AuthenticationConfig{
|
||||
AuthFunc: auth.AuthenticateUser,
|
||||
RedirectURL: "/login",
|
||||
|
|
|
@ -3,15 +3,12 @@ package auth
|
|||
import (
|
||||
"AABBCCDD/app/db"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/anthdm/superkit/event"
|
||||
"github.com/anthdm/superkit/kit"
|
||||
"github.com/anthdm/superkit/mail"
|
||||
v "github.com/anthdm/superkit/validate"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
|
@ -27,27 +24,15 @@ var authSchema = v.Schema{
|
|||
"password": v.Rules(v.Required),
|
||||
}
|
||||
|
||||
var signupSchema = v.Schema{
|
||||
"email": v.Rules(v.Email),
|
||||
"password": v.Rules(
|
||||
v.ContainsSpecial,
|
||||
v.ContainsUpper,
|
||||
v.Min(7),
|
||||
v.Max(50),
|
||||
),
|
||||
"firstName": v.Rules(v.Min(2), v.Max(50)),
|
||||
"lastName": v.Rules(v.Min(2), v.Max(50)),
|
||||
}
|
||||
|
||||
func HandleAuthIndex(kit *kit.Kit) error {
|
||||
func HandleLoginIndex(kit *kit.Kit) error {
|
||||
if kit.Auth().Check() {
|
||||
redirectURL := kit.Getenv("SUPERKIT_AUTH_REDIRECT_AFTER_LOGIN", "/profile")
|
||||
return kit.Redirect(http.StatusSeeOther, redirectURL)
|
||||
}
|
||||
return kit.Render(AuthIndex(AuthIndexPageData{}))
|
||||
return kit.Render(LoginIndex(LoginIndexPageData{}))
|
||||
}
|
||||
|
||||
func HandleAuthCreate(kit *kit.Kit) error {
|
||||
func HandleLoginCreate(kit *kit.Kit) error {
|
||||
var values LoginFormValues
|
||||
errors, ok := v.Request(kit.Request, &values, authSchema)
|
||||
if !ok {
|
||||
|
@ -109,7 +94,7 @@ func HandleAuthCreate(kit *kit.Kit) error {
|
|||
return kit.Redirect(http.StatusSeeOther, redirectURL)
|
||||
}
|
||||
|
||||
func HandleAuthDelete(kit *kit.Kit) error {
|
||||
func HandleLoginDelete(kit *kit.Kit) error {
|
||||
sess := kit.GetSession(userSessionName)
|
||||
defer func() {
|
||||
sess.Values = map[any]any{}
|
||||
|
@ -125,52 +110,6 @@ func HandleAuthDelete(kit *kit.Kit) error {
|
|||
return kit.Redirect(http.StatusSeeOther, "/")
|
||||
}
|
||||
|
||||
func HandleSignupIndex(kit *kit.Kit) error {
|
||||
return kit.Render(SignupIndex(SignupIndexPageData{}))
|
||||
}
|
||||
|
||||
func HandleSignupCreate(kit *kit.Kit) error {
|
||||
var values SignupFormValues
|
||||
errors, ok := v.Request(kit.Request, &values, signupSchema)
|
||||
if !ok {
|
||||
return kit.Render(SignupForm(values, errors))
|
||||
}
|
||||
if values.Password != values.PasswordConfirm {
|
||||
errors.Add("passwordConfirm", "passwords do not match")
|
||||
return kit.Render(SignupForm(values, errors))
|
||||
}
|
||||
user, err := createUserFromFormValues(values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token, err := createVerificationToken(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event.Emit("user.signup", user)
|
||||
mail.NOOPMailer{}.SendEmail(kit.Request.Context(), mail.Contents{
|
||||
Title: token,
|
||||
})
|
||||
return kit.Render(ConfirmEmail(user.Email))
|
||||
}
|
||||
|
||||
func createVerificationToken(userID int) (string, error) {
|
||||
expiryStr := kit.Getenv("SUPERKIT_AUTH_EMAIL_VERIFICATION_EXPIRY_IN_HOURS", "1")
|
||||
expiry, err := strconv.Atoi(expiryStr)
|
||||
if err != nil {
|
||||
expiry = 1
|
||||
}
|
||||
|
||||
claims := jwt.RegisteredClaims{
|
||||
Subject: fmt.Sprint(userID),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(expiry))),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString([]byte(os.Getenv("SUPERKIT_SECRET")))
|
||||
}
|
||||
|
||||
func HandleEmailVerify(kit *kit.Kit) error {
|
||||
tokenStr := kit.Request.URL.Query().Get("token")
|
||||
if len(tokenStr) == 0 {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"AABBCCDD/app/views/components"
|
||||
)
|
||||
|
||||
type AuthIndexPageData struct {
|
||||
type LoginIndexPageData struct {
|
||||
FormValues LoginFormValues
|
||||
FormErrors v.Errors
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ type LoginFormValues struct {
|
|||
Password string `form:"password"`
|
||||
}
|
||||
|
||||
templ AuthIndex(data AuthIndexPageData) {
|
||||
templ LoginIndex(data LoginIndexPageData) {
|
||||
@layouts.BaseLayout() {
|
||||
<div class="fixed top-6 right-6">
|
||||
@components.ThemeSwitcher()
|
|
@ -15,9 +15,9 @@ func InitializeRoutes(router chi.Router) {
|
|||
|
||||
router.Group(func(auth chi.Router) {
|
||||
auth.Use(kit.WithAuthentication(authConfig, false))
|
||||
auth.Get("/login", kit.Handler(HandleAuthIndex))
|
||||
auth.Post("/login", kit.Handler(HandleAuthCreate))
|
||||
auth.Delete("/logout", kit.Handler(HandleAuthDelete))
|
||||
auth.Get("/login", kit.Handler(HandleLoginIndex))
|
||||
auth.Post("/login", kit.Handler(HandleLoginCreate))
|
||||
auth.Delete("/logout", kit.Handler(HandleLoginDelete))
|
||||
|
||||
auth.Get("/signup", kit.Handler(HandleSignupIndex))
|
||||
auth.Post("/signup", kit.Handler(HandleSignupCreate))
|
||||
|
|
71
bootstrap/plugins/auth/signup_handler.go
Normal file
71
bootstrap/plugins/auth/signup_handler.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/anthdm/superkit/event"
|
||||
"github.com/anthdm/superkit/kit"
|
||||
v "github.com/anthdm/superkit/validate"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
var signupSchema = v.Schema{
|
||||
"email": v.Rules(v.Email),
|
||||
"password": v.Rules(
|
||||
v.ContainsSpecial,
|
||||
v.ContainsUpper,
|
||||
v.Min(7),
|
||||
v.Max(50),
|
||||
),
|
||||
"firstName": v.Rules(v.Min(2), v.Max(50)),
|
||||
"lastName": v.Rules(v.Min(2), v.Max(50)),
|
||||
}
|
||||
|
||||
func HandleSignupIndex(kit *kit.Kit) error {
|
||||
return kit.Render(SignupIndex(SignupIndexPageData{}))
|
||||
}
|
||||
|
||||
func HandleSignupCreate(kit *kit.Kit) error {
|
||||
var values SignupFormValues
|
||||
errors, ok := v.Request(kit.Request, &values, signupSchema)
|
||||
if !ok {
|
||||
return kit.Render(SignupForm(values, errors))
|
||||
}
|
||||
if values.Password != values.PasswordConfirm {
|
||||
errors.Add("passwordConfirm", "passwords do not match")
|
||||
return kit.Render(SignupForm(values, errors))
|
||||
}
|
||||
user, err := createUserFromFormValues(values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token, err := createVerificationToken(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event.Emit("auth.signup", UserWithVerificationToken{
|
||||
Token: token,
|
||||
User: user,
|
||||
})
|
||||
return kit.Render(ConfirmEmail(user.Email))
|
||||
}
|
||||
|
||||
func createVerificationToken(userID int) (string, error) {
|
||||
expiryStr := kit.Getenv("SUPERKIT_AUTH_EMAIL_VERIFICATION_EXPIRY_IN_HOURS", "1")
|
||||
expiry, err := strconv.Atoi(expiryStr)
|
||||
if err != nil {
|
||||
expiry = 1
|
||||
}
|
||||
|
||||
claims := jwt.RegisteredClaims{
|
||||
Subject: fmt.Sprint(userID),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(expiry))),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString([]byte(os.Getenv("SUPERKIT_SECRET")))
|
||||
}
|
|
@ -8,6 +8,13 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// UserWithVerificationToken is a struct that will be sent over the
|
||||
// auth.signup event. It holds the User struct and the Verification token string.
|
||||
type UserWithVerificationToken struct {
|
||||
User User
|
||||
Token string
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
UserID int
|
||||
Email string
|
||||
|
|
Loading…
Reference in a new issue