找回密码(未完)

dev
truthhun 1 year ago
parent de48daca20
commit 2b8a192b14

@ -43,7 +43,7 @@ message RegisterAndLoginRequest {
string password = 2 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
string captcha = 3;
string captcha_id = 4;
string email = 5;
string email = 5;
}
message GetUserCaptchaRequest {
@ -60,6 +60,14 @@ message DeleteUserRequest { repeated int64 id = 1; }
message GetUserRequest { int64 id = 1; }
message FindPasswordRequest {
string email = 1;
string token = 2;
string password = 3 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
string captcha = 4;
string captcha_id = 5;
}
message ListUserRequest {
int64 page = 1;
int64 size = 2;
@ -120,7 +128,7 @@ message ListUserDynamicReply {
repeated Dynamic dynamic = 2;
}
message Sign{
message Sign {
int64 id = 1;
int64 user_id = 2;
int32 sign_at = 3;
@ -253,38 +261,17 @@ service UserAPI {
};
}
//
// rpc ListUserFans(ListUserFansRequest) returns (ListUserReply) {
// option (google.api.http) = {
// get : '/api/v1/user/fans',
// };
// }
// //
// rpc ListUserFollow(ListUserFollowRequest) returns (ListUserReply) {
// option (google.api.http) = {
// get : '/api/v1/user/follow',
// };
// }
// //
// rpc ListUserFavorite(ListUserFavoriteRequest) returns (ListUserReply) {
// option (google.api.http) = {
// get : '/api/v1/user/favorite',
// };
// }
// //
// rpc ListUserDocument(ListUserDocumentRequest) returns (ListUserReply) {
// option (google.api.http) = {
// get : '/api/v1/user/document',
// };
// }
// //
// rpc ListUserComment(ListUserCommentRequest) returns (ListUserReply) {
// option (google.api.http) = {
// get : '/api/v1/user/comment',
// };
// }
rpc FindPasswordStepOne(FindPasswordRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post : '/api/v1/user/findpassword/stepone',
body : '*',
};
}
rpc FindPasswordStepTwo(FindPasswordRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
put : '/api/v1/user/findpassword/steptwo',
body : '*',
};
}
}

@ -3,6 +3,7 @@ package biz
import (
"context"
"fmt"
"net/url"
"strings"
"time"
@ -16,6 +17,7 @@ import (
"moredoc/util/captcha"
"github.com/alexandrevicenzi/unchained"
"github.com/golang-jwt/jwt"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -605,3 +607,80 @@ func (s *UserAPIService) ListUserDynamic(ctx context.Context, req *v1.ListUserDy
return &v1.ListUserDynamicReply{Dynamic: pbDynamics, Total: total}, nil
}
// 找回密码:发送邮件
func (s *UserAPIService) FindPasswordStepOne(ctx context.Context, req *v1.FindPasswordRequest) (res *emptypb.Empty, err error) {
if !util.IsValidEmail(req.Email) {
return nil, status.Errorf(codes.InvalidArgument, "邮箱格式不正确")
}
cfgSec := s.dbModel.GetConfigOfSecurity(model.ConfigSecurityEnableCaptchaFindPassword)
if cfgSec.EnableCaptchaFindPassword && !captcha.VerifyCaptcha(req.CaptchaId, req.Captcha) {
return nil, status.Errorf(codes.InvalidArgument, "验证码错误")
}
user, _ := s.dbModel.GetUserByEmail(req.Email, "id")
if user.Id == 0 {
return nil, status.Errorf(codes.NotFound, "用户不存在")
}
cfgEmail := s.dbModel.GetConfigOfEmail()
if !cfgEmail.Enable {
return nil, status.Errorf(codes.Internal, "邮件服务未启用,请联系管理员")
}
cfgSystem := s.dbModel.GetConfigOfSystem()
cfgEmail.Duration = util.LimitRange(cfgEmail.Duration, 1, 60)
// 使用JWT创建token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
Id: req.Email,
ExpiresAt: time.Now().Add(time.Minute * time.Duration(cfgEmail.Duration)).Unix(),
})
tokenString, err := token.SignedString([]byte(cfgEmail.Secret))
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
link := fmt.Sprintf("%s/findpassword?token=%s&email=%s", strings.TrimRight(cfgSystem.Domain, "/"), tokenString, url.QueryEscape(req.Email))
body := fmt.Sprintf(`
<div class="wrapper" style="margin: 20px auto 0; width: 500px; padding-top:16px; padding-bottom:10px;">
<div class="content" style="background: none repeat scroll 0 0 #FFFFFF; border: 1px solid #E9E9E9; margin: 2px 0 0; padding: 30px;">
<p>: </p>
<p> <a href="%s">%s</a> <br>, </p>
<p style="border-top: 1px solid #DDDDDD;margin: 15px 0 25px;padding: 15px;">
: <a href="%s" target="_blank">%s</a>
</p>
<p>
<ul>
<li></li>
<li> 6 </li>
<li></li>
</ul>
</p>
</div>
</div>
`,
cfgSystem.Domain,
cfgSystem.Sitename,
link,
link,
)
// 发送邮件
err = s.dbModel.SendMail(
"找回密码 - "+cfgSystem.Sitename,
req.Email,
body,
)
if err != nil {
s.logger.Error("发送邮件失败", zap.Error(err))
return nil, status.Errorf(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// 找回密码:重置密码
func (s *UserAPIService) FindPasswordStepTwo(ctx context.Context, req *v1.FindPasswordRequest) (res *emptypb.Empty, err error) {
return
}

@ -199,7 +199,7 @@ const (
type ConfigSystem struct {
Sitename string `json:"sitename"` // 网站名称
Domain string `json:"domain"` // 站点域名,不带 HTTPS:// 和 HTTP://
Domain string `json:"domain"` // 站点域名,带 HTTPS:// 或 HTTP://
Title string `json:"title"` // 网站首页标题
Keywords string `json:"keywords"` // 系统关键字
Description string `json:"description"` // 系统描述
@ -289,6 +289,7 @@ const (
ConfigEmailDuration = "duration" // 验证码有效期,单位为分钟
ConfigEmailTestEmail = "test_email"
ConfigEmailReplyTo = "reply_to"
ConfigEmailSecret = "secret" // 找回密码邮件的签名密钥
)
type ConfigEmail struct {
@ -301,6 +302,7 @@ type ConfigEmail struct {
Password string `json:"password"`
Duration int `json:"duration"` // 验证码有效期,单位为分钟
TestEmail string `json:"test_email"`
Secret string `json:"secret"`
// ReplyTo string `json:"reply_to"`
}
@ -623,7 +625,7 @@ func (m *DBModel) initConfig() (err error) {
{Category: ConfigCategorySystem, Name: ConfigSystemRegistrerBackground, Label: "注册页背景图", Value: "", Placeholder: "请上传一张图片作为注册页背景图", InputType: "image", Sort: 62, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemLoginBackground, Label: "登录页背景图", Value: "", Placeholder: "请上传一张图片作为登录页背景图", InputType: "image", Sort: 63, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemIcp, Label: "网站备案号", Value: "", Placeholder: "请输入您网站的备案号", InputType: "text", Sort: 69, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemDomain, Label: "网站域名", Value: "https://moredoc.mnt.ltd", Placeholder: "请输入您网站的域名访问地址,如 https://moredoc.mnt.ltd用以生成网站地图sitemap", InputType: "text", Sort: 70, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemDomain, Label: "网站域名", Value: "https://moredoc.mnt.ltd", Placeholder: "请输入您网站的域名访问地址,带 https:// 或 http:// 如 https://moredoc.mnt.ltd用以生成网站地图sitemap", InputType: "text", Sort: 70, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemCopyrightStartYear, Label: "版权起始年", Value: "2019", Placeholder: "请输入您网站版权起始年2019则前台会显示如 ©2019 - 2022 的字样", InputType: "text", Sort: 80, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemAnalytics, Label: "网站统计代码", Value: "", Placeholder: "请输入您网站的统计代码", InputType: "textarea", Sort: 90, Options: ""},
@ -686,6 +688,7 @@ func (m *DBModel) initConfig() (err error) {
{Category: ConfigCategoryEmail, Name: ConfigEmailUsername, Label: "SMTP 账号", Value: "", Placeholder: "请输入您的邮箱账户", InputType: "text", Sort: 60, Options: ""},
{Category: ConfigCategoryEmail, Name: ConfigEmailPassword, Label: "SMTP 密码", Value: "", Placeholder: "请输入您的邮箱密码", InputType: "password", Sort: 70, Options: ""},
{Category: ConfigCategoryEmail, Name: ConfigEmailDuration, Label: "邮件有效期", Value: "30", Placeholder: "找回密码时链接有效期默认为30表示30分钟", InputType: "number", Sort: 80, Options: ""},
{Category: ConfigCategoryEmail, Name: ConfigEmailSecret, Label: "签名密钥", Value: "moredoc", Placeholder: "找回密码链接签名密钥", InputType: "text", Sort: 80, Options: ""},
{Category: ConfigCategoryEmail, Name: ConfigEmailTestEmail, Label: "测试邮箱", Value: "", Placeholder: "用于每次变更配置时保存发送测试邮件", InputType: "text", Sort: 90, Options: ""},
}

@ -1,6 +1,9 @@
<template>
<div class="page-index">
{{ $route.name }}
<div class="page page-findpassword">
<el-card shadow="never">
<div slot="header">找回密码</div>
谁谁谁
</el-card>
</div>
</template>

Loading…
Cancel
Save