for save
This commit is contained in:
@@ -11,40 +11,49 @@ import (
|
||||
|
||||
var EmailManager *EmailSender
|
||||
|
||||
type EmailFormat struct {
|
||||
TargetEmail string // 发送的目标email
|
||||
CompanyName string // fs公司名
|
||||
ConfirmationLink string // fs确认连接
|
||||
SenderName string // 发送人
|
||||
SenderTitle string // 发送标题
|
||||
}
|
||||
|
||||
// EmailSender
|
||||
type EmailSender struct {
|
||||
lock sync.Mutex
|
||||
EmailTasks chan string
|
||||
EmailTasks chan *EmailFormat
|
||||
Auth smtp.Auth
|
||||
FromEmail string
|
||||
emailSending map[string]*EmailTask
|
||||
ResendTimeLimit time.Duration
|
||||
semaphore chan struct{}
|
||||
|
||||
emailSending map[string]*EmailTask
|
||||
semaphore chan struct{}
|
||||
}
|
||||
|
||||
// EmailTask
|
||||
type EmailTask struct {
|
||||
Email string // email
|
||||
SendTime time.Time // 处理的任务时间
|
||||
Email *EmailFormat // email
|
||||
SendTime time.Time // 处理的任务时间
|
||||
}
|
||||
|
||||
func (m *EmailSender) ProcessEmailTasks() {
|
||||
for {
|
||||
emailTarget, ok := <-m.EmailTasks
|
||||
emailformat, ok := <-m.EmailTasks
|
||||
if !ok {
|
||||
log.Println("Email task channel closed")
|
||||
break
|
||||
}
|
||||
|
||||
m.lock.Lock()
|
||||
_, isSending := m.emailSending[emailTarget]
|
||||
_, isSending := m.emailSending[emailformat.TargetEmail]
|
||||
if isSending {
|
||||
m.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
m.emailSending[emailTarget] = &EmailTask{
|
||||
Email: emailTarget,
|
||||
m.emailSending[emailformat.TargetEmail] = &EmailTask{
|
||||
Email: emailformat,
|
||||
SendTime: time.Now(),
|
||||
}
|
||||
m.lock.Unlock()
|
||||
@@ -55,11 +64,11 @@ func (m *EmailSender) ProcessEmailTasks() {
|
||||
go func() {
|
||||
defer func() { <-m.semaphore }() // Release a token
|
||||
|
||||
content := RenderEmailTemplate("fusen", "http://www.baidu.com", "fusen@gmail.com", "mail-valid")
|
||||
err := smtp.SendMail("smtp.gmail.com:587", m.Auth, m.FromEmail, []string{emailTarget}, content)
|
||||
content := RenderEmailTemplate(emailformat.CompanyName, emailformat.ConfirmationLink, emailformat.SenderName, emailformat.SenderTitle)
|
||||
err := smtp.SendMail("smtp.gmail.com:587", m.Auth, m.FromEmail, []string{emailformat.TargetEmail}, content)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send email to %s: %v\n", emailTarget, err)
|
||||
m.Resend(emailTarget, content)
|
||||
log.Printf("Failed to send email to %s: %v\n", emailformat, err)
|
||||
m.Resend(emailformat.TargetEmail, content)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -105,7 +114,7 @@ func init() {
|
||||
|
||||
// Initialize the email manager
|
||||
EmailManager = &EmailSender{
|
||||
EmailTasks: make(chan string, 10),
|
||||
EmailTasks: make(chan *EmailFormat, 10),
|
||||
Auth: smtp.PlainAuth(
|
||||
"",
|
||||
"user@example.com",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fusenapi/model/gmodel"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
@@ -10,6 +12,7 @@ import (
|
||||
"fusenapi/server/auth/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserEmailConfirmationLogic struct {
|
||||
@@ -34,6 +37,43 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma
|
||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||
// userinfo 传入值时, 一定不为null
|
||||
|
||||
token, err := l.svcCtx.TokenManger.Decrypt(req.Token)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
switch token.OperateType {
|
||||
case auth.OpTypeRegister:
|
||||
if time.Since(token.CreateAt) >= 24*time.Hour {
|
||||
return resp.SetStatus(basic.CodeOAuthConfirmationTimeoutErr)
|
||||
}
|
||||
|
||||
switch token.Platform {
|
||||
case "google":
|
||||
|
||||
user, err := l.OpGoogleRegister(token)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeDbSqlErr)
|
||||
}
|
||||
|
||||
jwtToken, err := auth.GenerateJwtTokenUint64(
|
||||
auth.StringToHash(*user.PasswordHash),
|
||||
l.svcCtx.Config.Auth.AccessExpire,
|
||||
time.Now().Unix(),
|
||||
user.Id,
|
||||
0,
|
||||
)
|
||||
|
||||
case "facebook":
|
||||
l.OpGoogleRegister(token)
|
||||
}
|
||||
|
||||
default:
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
return resp.SetStatus(basic.CodeOK)
|
||||
}
|
||||
|
||||
@@ -41,3 +81,41 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma
|
||||
// func (l *UserEmailConfirmationLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
// }
|
||||
|
||||
// OpGoogleRegister 谷歌平台的注册流程
|
||||
func (l *UserEmailConfirmationLogic) OpGoogleRegister(token *auth.RegisterToken) (*gmodel.FsUser, error) {
|
||||
user := &gmodel.FsUser{}
|
||||
|
||||
err := l.svcCtx.AllModels.FsUser.Transaction(context.TODO(), func(tx *gorm.DB) error {
|
||||
|
||||
err := tx.Model(user).Where("email = ?", token.Email).Take(user).Error
|
||||
if err != nil {
|
||||
// 没有找到在数据库就创建注册
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
createAt := time.Now().Unix()
|
||||
user.Email = &token.Email
|
||||
user.CreatedAt = &createAt
|
||||
user.GoogleId = &token.Id
|
||||
user.PasswordHash = &token.Password
|
||||
err = tx.Model(user).Create(user).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 继承guest_id的资源表
|
||||
// tx.Table("fs_resources").Model()
|
||||
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
user.GoogleId = &token.Id
|
||||
return tx.Model(user).Update("google_id", user).Error
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@@ -39,5 +39,42 @@ func (l *UserEmailRegisterLogic) UserEmailRegister(req *types.RequestEmailRegist
|
||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||
// userinfo 传入值时, 一定不为null
|
||||
|
||||
// 进入邮件注册流程
|
||||
// 这里是注册模块, 发邮件, 通过邮件注册确认邮箱存在
|
||||
|
||||
// 邮箱验证格式错误
|
||||
if !auth.ValidateEmail(req.Email) {
|
||||
return resp.SetStatus(basic.CodeOAuthEmailErr)
|
||||
}
|
||||
|
||||
token, err := l.svcCtx.TokenManger.Decrypt(req.RegisterToken)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
if token.OperateType != auth.OpTypeRegister {
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
// 确认email 重新序列化
|
||||
token.Email = req.Email
|
||||
token.WCId = req.WCId
|
||||
|
||||
clurl, err := l.svcCtx.TokenManger.Generate(token)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
// 进入发送邮箱的系统
|
||||
EmailManager.EmailTasks <- &EmailFormat{
|
||||
TargetEmail: req.Email,
|
||||
CompanyName: "fusen",
|
||||
ConfirmationLink: clurl,
|
||||
SenderName: "support@fusenpack.com",
|
||||
SenderTitle: "register-valid",
|
||||
} // email进入队
|
||||
|
||||
return resp.SetStatus(basic.CodeOK)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -46,52 +49,6 @@ func NewUserGoogleLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *U
|
||||
// func (l *UserGoogleLoginLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
|
||||
<<<<<<< HEAD
|
||||
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||
func (l *UserGoogleLoginLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||
|
||||
if resp.Code == 200 {
|
||||
|
||||
if !l.isRegistered {
|
||||
|
||||
rtoken, err := l.svcCtx.TokenManger.Encrypt(l.registerInfo)
|
||||
if err != nil {
|
||||
resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
l.registerToken = rtoken
|
||||
}
|
||||
|
||||
rurl := fmt.Sprintf(
|
||||
l.svcCtx.Config.MainAddress+"/oauth?token=%s&is_registered=%t®ister_token=%s",
|
||||
l.token,
|
||||
l.isRegistered,
|
||||
l.registerToken,
|
||||
)
|
||||
|
||||
html := fmt.Sprintf(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Redirect</title>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
window.location = "%s";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
`, rurl)
|
||||
fmt.Fprintln(w, html)
|
||||
} else {
|
||||
httpx.OkJson(w, resp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> 529a02ac7582babc634e6f9cddab126f5f962efb
|
||||
func (l *UserGoogleLoginLogic) UserGoogleLogin(req *types.RequestGoogleLogin, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||
// userinfo 传入值时, 一定不为null
|
||||
@@ -141,30 +98,34 @@ func (l *UserGoogleLoginLogic) UserGoogleLogin(req *types.RequestGoogleLogin, us
|
||||
return resp.SetStatus(basic.CodeDbSqlErr)
|
||||
}
|
||||
|
||||
nonce := make([]byte, 16)
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeOK)
|
||||
}
|
||||
|
||||
l.registerInfo = &auth.RegisterToken{
|
||||
Id: googleId,
|
||||
Password: base64.URLEncoding.EncodeToString(nonce),
|
||||
Platform: "google",
|
||||
OperateType: auth.OpTypeRegister,
|
||||
CreateAt: time.Now(),
|
||||
}
|
||||
|
||||
l.isRegistered = false
|
||||
l.registerToken = //
|
||||
|
||||
// 进入邮件注册流程
|
||||
// if req.Email == "" {
|
||||
// return resp.SetStatus(basic.CodeOK)
|
||||
// }
|
||||
|
||||
// // 这里是注册模块, 发邮件, 通过邮件注册确认邮箱存在
|
||||
|
||||
// // 邮箱验证格式错误
|
||||
// if !auth.ValidateEmail(req.Email) {
|
||||
// return resp.SetStatus(basic.CodeOAuthEmailErr)
|
||||
// }
|
||||
|
||||
// EmailManager.EmailTasks <- req.Email // email进入队
|
||||
token, err := l.svcCtx.TokenManger.Encrypt(l.registerInfo)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
l.registerToken = token
|
||||
|
||||
return resp.SetStatus(basic.CodeOK)
|
||||
}
|
||||
|
||||
l.isRegistered = true
|
||||
// 如果密码匹配,则生成 JWT Token。
|
||||
nowSec := time.Now().Unix()
|
||||
|
||||
jwtToken, err := auth.GenerateJwtTokenUint64(auth.StringToHash(*user.PasswordHash), l.svcCtx.Config.Auth.AccessExpire, nowSec, user.Id, 0)
|
||||
jwtToken, err := auth.GenerateJwtTokenUint64(auth.StringToHash(*user.PasswordHash), l.svcCtx.Config.Auth.AccessExpire, time.Now().Unix(), user.Id, 0)
|
||||
|
||||
// 如果生成 JWT Token 失败,则抛出错误并返回未认证的状态码。
|
||||
if err != nil {
|
||||
@@ -182,23 +143,6 @@ func (l *UserGoogleLoginLogic) AfterLogic(w http.ResponseWriter, r *http.Request
|
||||
|
||||
if resp.Code == 200 {
|
||||
|
||||
if !l.isRegistered {
|
||||
now := time.Now()
|
||||
rtoken, err := auth.GenerateRegisterToken(
|
||||
&l.svcCtx.Config.Auth.AccessSecret,
|
||||
l.svcCtx.Config.Auth.AccessExpire,
|
||||
now.Unix(),
|
||||
l.oauthinfo.Id,
|
||||
l.oauthinfo.Platform,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
|
||||
}
|
||||
|
||||
l.registerToken = rtoken
|
||||
}
|
||||
|
||||
rurl := fmt.Sprintf(
|
||||
l.svcCtx.Config.MainAddress+"/oauth?token=%s&is_registered=%t®ister_token=%s",
|
||||
l.token,
|
||||
|
||||
Reference in New Issue
Block a user