改为 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
import (
"bytes"
"context"
"crypto/rsa"
"errors"
"fmt"
"html/template"
"math/rand"
"net/url"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/samber/lo"
"github.com/wneessen/go-mail"
"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
}
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)
sendB, err := e.cache.Get(sendKey)
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
return fmt.Errorf("SendVerifyUrl: %w", err)
}
if sendB == nil {
return fmt.Errorf("SendRegVerifyCode: %w", ErrSendLimit)
if sendB != nil {
return fmt.Errorf("SendVerifyUrl: %w", ErrSendLimit)
}
err = e.cache.Put(sendKey, []byte{1}, time.Now().Add(time.Second*time.Duration(interval)))
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
return fmt.Errorf("SendVerifyUrl: %w", err)
}
code := lo.RandomString(8, append(lo.NumbersCharset, lo.UpperCaseLettersCharset...))
err = e.cache.Put([]byte("VerifyCode"+email), []byte(code), time.Now().Add(5*time.Minute))
code, err := newJwtToken(e.pri, email)
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 {
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
}
@ -106,20 +135,33 @@ func (e Email) SendVerifyCode(ctx context.Context, email string, interval int) e
var (
ErrCodeNotValid = errors.New("验证码无效")
ErrSendLimit = errors.New("邮件发送限制")
ErrTokenInvalid = errors.New("token 无效")
)
func (e Email) VerifyCode(email, code string) error {
key := []byte("VerifyCode" + email)
codeb, err := e.cache.Get(key)
func (e Email) VerifyJwt(email, jwtStr string) error {
token, err := jwt.ParseWithClaims(jwtStr, &jwt.RegisteredClaims{}, func(t *jwt.Token) (interface{}, error) {
return e.pri.PublicKey, nil
})
if err != nil {
return fmt.Errorf("VerifyCode: %w", err)
return fmt.Errorf("VerifyJwt: %w", err)
}
if string(codeb) != code {
err := e.cache.Del(key)
if err != nil {
return fmt.Errorf("VerifyCode: %w", err)
}
return ErrCodeNotValid
sub, _ := token.Claims.GetSubject()
if !token.Valid || sub != email {
return fmt.Errorf("VerifyJwt: %w", ErrTokenInvalid)
}
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
}