改为 jwt
This commit is contained in:
parent
ed4725e179
commit
cd66d3823e
@ -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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user