改为 jwt

This commit is contained in:
xmdhs 2023-11-24 14:00:42 +08:00
parent ed4725e179
commit cd66d3823e
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95

View File

@ -1,13 +1,17 @@
package email package email
import ( import (
"bytes"
"context" "context"
"crypto/rsa" "crypto/rsa"
"errors" "errors"
"fmt" "fmt"
"html/template"
"math/rand" "math/rand"
"net/url"
"time" "time"
"github.com/golang-jwt/jwt/v5"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/wneessen/go-mail" "github.com/wneessen/go-mail"
"github.com/xmdhs/authlib-skin/config" "github.com/xmdhs/authlib-skin/config"
@ -76,29 +80,54 @@ func (e Email) SendEmail(ctx context.Context, to string, subject, body string) e
return nil return nil
} }
func (e Email) SendVerifyCode(ctx context.Context, email string, interval int) error { var emailTemplate = lo.Must(template.New("email").Parse(`<p>{{ .msg }}</p><a href="{{.url}}">{{ .url }}</a>`))
func (e Email) SendVerifyUrl(ctx context.Context, email string, interval int, host string) error {
sendKey := []byte("SendEmail" + email) sendKey := []byte("SendEmail" + email)
sendB, err := e.cache.Get(sendKey) sendB, err := e.cache.Get(sendKey)
if err != nil { if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err) return fmt.Errorf("SendVerifyUrl: %w", err)
} }
if sendB == nil { if sendB != nil {
return fmt.Errorf("SendRegVerifyCode: %w", ErrSendLimit) return fmt.Errorf("SendVerifyUrl: %w", ErrSendLimit)
} }
err = e.cache.Put(sendKey, []byte{1}, time.Now().Add(time.Second*time.Duration(interval))) err = e.cache.Put(sendKey, []byte{1}, time.Now().Add(time.Second*time.Duration(interval)))
if err != nil { if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err) return fmt.Errorf("SendVerifyUrl: %w", err)
} }
code := lo.RandomString(8, append(lo.NumbersCharset, lo.UpperCaseLettersCharset...)) code, err := newJwtToken(e.pri, email)
err = e.cache.Put([]byte("VerifyCode"+email), []byte(code), time.Now().Add(5*time.Minute))
if err != nil { if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err) return fmt.Errorf("SendVerifyUrl: %w", err)
} }
err = e.SendEmail(ctx, email, "验证你的邮箱", fmt.Sprintf("验证码:%v五分钟内有效", code))
u := url.URL{
Host: host,
Scheme: "http",
Path: "/test?" + code,
}
if e.config.WebBaseUrl != "" {
webBase, err := url.Parse(e.config.WebBaseUrl)
if err != nil {
return fmt.Errorf("SendVerifyUrl: %w", err)
}
u.Host = webBase.Host
u.Scheme = webBase.Scheme
}
body := bytes.NewBuffer(nil)
err = emailTemplate.Execute(body, map[string]any{
"msg": "点击下方链接验证你的邮箱1 天内有效",
"url": u.String(),
})
if err != nil { if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err) return fmt.Errorf("SendVerifyUrl: %w", err)
}
err = e.SendEmail(ctx, email, "验证你的邮箱", body.String())
if err != nil {
return fmt.Errorf("SendVerifyUrl: %w", err)
} }
return nil return nil
} }
@ -106,20 +135,33 @@ func (e Email) SendVerifyCode(ctx context.Context, email string, interval int) e
var ( var (
ErrCodeNotValid = errors.New("验证码无效") ErrCodeNotValid = errors.New("验证码无效")
ErrSendLimit = errors.New("邮件发送限制") ErrSendLimit = errors.New("邮件发送限制")
ErrTokenInvalid = errors.New("token 无效")
) )
func (e Email) VerifyCode(email, code string) error { func (e Email) VerifyJwt(email, jwtStr string) error {
key := []byte("VerifyCode" + email) token, err := jwt.ParseWithClaims(jwtStr, &jwt.RegisteredClaims{}, func(t *jwt.Token) (interface{}, error) {
codeb, err := e.cache.Get(key) return e.pri.PublicKey, nil
})
if err != nil { if err != nil {
return fmt.Errorf("VerifyCode: %w", err) return fmt.Errorf("VerifyJwt: %w", err)
} }
if string(codeb) != code { sub, _ := token.Claims.GetSubject()
err := e.cache.Del(key) if !token.Valid || sub != email {
if err != nil { return fmt.Errorf("VerifyJwt: %w", ErrTokenInvalid)
return fmt.Errorf("VerifyCode: %w", err)
}
return ErrCodeNotValid
} }
return nil return nil
} }
func newJwtToken(jwtKey *rsa.PrivateKey, email string) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * 24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Subject: email,
Issuer: "authlib-skin email verification",
})
jwts, err := token.SignedString(jwtKey)
if err != nil {
return "", fmt.Errorf("newJwtToken: %w", err)
}
return jwts, nil
}