TODO: password

This commit is contained in:
eson 2023-09-04 01:40:28 +08:00
parent 31f46b64b5
commit 9c89f0fe4a
6 changed files with 97 additions and 27 deletions

View File

@ -92,14 +92,15 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
switch auth.OperateType(req.OpType) {
case auth.OpTypeRegister:
token, err := l.svcCtx.OAuthTokenManger.Decrypt(req.Token) token, err := l.svcCtx.OAuthTokenManger.Decrypt(req.Token)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
} }
switch token.OperateType {
case auth.OpTypeRegister:
if time.Since(token.CreateAt) > 30*time.Minute { if time.Since(token.CreateAt) > 30*time.Minute {
return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "Verification links expire after 30 minute.") return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "Verification links expire after 30 minute.")
} }
@ -135,6 +136,36 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma
} }
logx.Info("success:", token.TraceId) logx.Info("success:", token.TraceId)
} }
case auth.OpTypeResetToken:
rt, err := l.svcCtx.ResetTokenManger.Decrypt(req.Token) // ResetToken
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeOAuthResetTokenDecryptErr, err.Error())
}
// TODO: 存储
if rt.OperateType != auth.OpTypeResetToken {
return resp.SetStatus(basic.CodeOAuthTypeErr, "error OperateType: rt.OperateType != auth.OpTypeResetToken")
}
err = l.svcCtx.AllModels.FsUser.Transaction(l.ctx, func(tx *gorm.DB) error {
user := &gmodel.FsUser{Id: int64(rt.UserId)}
err := tx.Take(user).Error
if err != nil {
return err
}
if *user.PasswordHash != rt.OldPassword {
return fmt.Errorf("password had beed updated")
}
return tx.Update("PasswordHash", rt.NewPassword).Error
})
if err != nil {
return resp.SetStatus(basic.CodeDbSqlErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
default: default:
return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)

View File

@ -49,6 +49,7 @@ type RequestGoogleLogin struct {
type RequestEmailConfirmation struct { type RequestEmailConfirmation struct {
Token string `form:"token"` // 操作Token Token string `form:"token"` // 操作Token
OpType string `form:"optype"` // 操作类型
} }
type RequestEmailRegister struct { type RequestEmailRegister struct {

View File

@ -103,6 +103,7 @@ type RequestGoogleLogin {
type RequestEmailConfirmation { type RequestEmailConfirmation {
Token string `form:"token"` // 操作Token Token string `form:"token"` // 操作Token
OpType string `form:"optype"` // 操作类型
} }
type RequestEmailRegister { type RequestEmailRegister {

View File

@ -1,22 +1,26 @@
package auth package auth
import ( import (
"fmt"
"fusenapi/utils/encryption_decryption" "fusenapi/utils/encryption_decryption"
"net/url" "net/url"
"reflect"
) )
type OperateType int8 type OperateType string
const ( const (
OpTypeRegister OperateType = 1 //注册的操作类型 OpTypeRegister OperateType = "1" //注册的操作类型
OpTypeResetToken OperateType = 2 //重置密码类型 OpTypeResetToken OperateType = "2" //重置密码类型
) )
type ConfirmationLink[T any] struct { type ConfirmationLink[T any] struct {
// Secret []byte // Secret []byte
SecretGCM *encryption_decryption.SecretGCM[T] secretGCM *encryption_decryption.SecretGCM[T]
defaultTokenKey string // 默认key 是 token
defaultOpTypeKey string
DefaultQueryKey string // 默认key 是 token
link *url.URL link *url.URL
} }
@ -27,31 +31,58 @@ func NewConfirmationLink[T any](key string, UrlStr string) *ConfirmationLink[T]
} }
return &ConfirmationLink[T]{ return &ConfirmationLink[T]{
SecretGCM: encryption_decryption.NewSecretGCM[T](key), secretGCM: encryption_decryption.NewSecretGCM[T](key),
DefaultQueryKey: "token", defaultTokenKey: "token",
defaultOpTypeKey: "optype",
link: u, link: u,
} }
} }
// WithDefaultTokenKey 设置默认Token Key
func (cl *ConfirmationLink[T]) WithDefaultTokenKey(tkey string) *ConfirmationLink[T] {
cl.defaultTokenKey = tkey
return cl
}
// WithDefaultOpTypeKey 设置默认OpType Key
func (cl *ConfirmationLink[T]) WithDefaultOpTypeKey(opkey string) *ConfirmationLink[T] {
cl.defaultTokenKey = opkey
return cl
}
// Generate 序列化链接传入需求的obj // Generate 序列化链接传入需求的obj
func (cl *ConfirmationLink[T]) Generate(obj *T) (string, error) { func (cl *ConfirmationLink[T]) Generate(obj *T) (string, error) {
vValue := reflect.ValueOf(obj).Elem()
opType := vValue.FieldByName("OperateType")
if !opType.IsValid() {
return "", fmt.Errorf("传入结构体 必须继承 OperateType")
}
op := opType.Interface().(OperateType)
token, err := cl.Encrypt(obj) token, err := cl.Encrypt(obj)
if err != nil { if err != nil {
return "", err return "", err
} }
return cl.GenerateWithToken(token) return cl.generateWithToken(token, op)
} }
// GenerateWithToken 序列化url带token // generateWithToken 序列化url带token
func (cl *ConfirmationLink[T]) GenerateWithToken(token string) (string, error) { func (cl *ConfirmationLink[T]) generateWithToken(token string, optype OperateType) (string, error) {
q := cl.link.Query() q := cl.link.Query()
if q.Has(cl.DefaultQueryKey) { if q.Has(cl.defaultTokenKey) {
q.Set(cl.DefaultQueryKey, token) q.Set(cl.defaultTokenKey, token)
} else { } else {
q.Add(cl.DefaultQueryKey, token) q.Add(cl.defaultTokenKey, token)
}
if q.Has(cl.defaultOpTypeKey) {
q.Set(cl.defaultOpTypeKey, string(optype))
} else {
q.Add(cl.defaultOpTypeKey, string(optype))
} }
// 生成确认链接 // 生成确认链接
@ -61,9 +92,9 @@ func (cl *ConfirmationLink[T]) GenerateWithToken(token string) (string, error) {
} }
func (cl *ConfirmationLink[T]) Encrypt(obj *T) (string, error) { func (cl *ConfirmationLink[T]) Encrypt(obj *T) (string, error) {
return cl.SecretGCM.Encrypt(obj) return cl.secretGCM.Encrypt(obj)
} }
func (cl *ConfirmationLink[T]) Decrypt(ciphertext string) (*T, error) { func (cl *ConfirmationLink[T]) Decrypt(ciphertext string) (*T, error) {
return cl.SecretGCM.Decrypt(ciphertext) return cl.secretGCM.Decrypt(ciphertext)
} }

View File

@ -116,6 +116,7 @@ func BenchmarkAesXor(b *testing.B) {
func TestConfirmationLink(t *testing.T) { func TestConfirmationLink(t *testing.T) {
type Register struct { type Register struct {
OperateType
Id int64 Id int64
Password string Password string
platform string platform string
@ -125,12 +126,16 @@ func TestConfirmationLink(t *testing.T) {
key := "21321321" key := "21321321"
cl := NewConfirmationLink[Register](key, "http://localhost:9900/api/auth/oauth2/register") cl := NewConfirmationLink[Register](key, "http://localhost:9900/api/auth/oauth2/register")
uri, _ := cl.Generate(&Register{Id: 39, Password: "21dsadsad", platform: "google", Expired: time.Now().UTC()}) robj := &Register{Id: 39, Password: "21dsadsad", platform: "google", Expired: time.Now().UTC(), OperateType: OpTypeResetToken}
uri, _ := cl.Generate(robj)
log.Println(uri) log.Println(uri)
u, _ := url.Parse(uri) u, _ := url.Parse(uri)
log.Println(uri)
token := u.Query()["token"] token := u.Query()["token"]
log.Println(cl.Decrypt(token[0])) log.Println(cl.Decrypt(token[0]))
} }
const secret = "your-256-bit-secret" const secret = "your-256-bit-secret"

View File

@ -42,6 +42,7 @@ type ResetToken struct {
UserId int64 // guest_id 需要继承 UserId int64 // guest_id 需要继承
Wid string // websocket 通道id Wid string // websocket 通道id
Email string // email Email string // email
NewPassword string // 新密码
OldPassword string // 旧密码 OldPassword string // 旧密码
TraceId string //链路Id TraceId string //链路Id
CreateAt time.Time // 创建时间 CreateAt time.Time // 创建时间