修改
This commit is contained in:
parent
3cff7a380f
commit
63d89c7a12
File diff suppressed because it is too large
Load Diff
@ -58,6 +58,42 @@ service Account {
|
||||
rpc Register (RegistRequest) returns (RegisterResponse) {}//注册
|
||||
rpc UserList (UserListRequest) returns (UserListResponse) {}//用户列表
|
||||
rpc CheckRealName (CheckRealNameRequest) returns (CheckRealNameResponse) {}//审核实名
|
||||
rpc GenerateSliderCaptcha(GenerateSliderCaptchaRequest) returns (GenerateSliderCaptchaResponse) {}// 生成滑块验证码图片+位置
|
||||
rpc VerifySliderCaptcha(VerifySliderCaptchaRequest) returns (VerifySliderCaptchaResponse) {}// 验证滑块验证码位置
|
||||
rpc SendNationMsg (SendNationMsgRequest) returns (SendMsgStatusResponse) {} //发送境外国际短信验证码 --艺术商城
|
||||
}
|
||||
message SendNationMsgRequest {
|
||||
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
|
||||
string TelNum = 2 [json_name = "telNum",(validator.field) = {string_not_empty: true,human_error: "70001"}];
|
||||
string Project = 3 [json_name = "project"];
|
||||
uint32 signNo = 4;
|
||||
uint32 mId = 5;
|
||||
string scope = 6;//标记模块
|
||||
}
|
||||
message VerifySliderCaptchaResponse {
|
||||
string nonceStr = 1;
|
||||
}
|
||||
|
||||
message VerifySliderCaptchaRequest {
|
||||
string nonceStr = 1;
|
||||
float blockX = 2;
|
||||
}
|
||||
message GenerateSliderCaptchaResponse {
|
||||
string nonceStr = 1;
|
||||
string canvasSrc = 2;
|
||||
string blockSrc = 3;
|
||||
uint64 blockY = 4;
|
||||
uint64 faceY = 5;
|
||||
uint64 blockX = 6;
|
||||
}
|
||||
|
||||
message GenerateSliderCaptchaRequest {
|
||||
uint64 canvasWidth = 1;
|
||||
uint64 canvasHeight = 2;
|
||||
uint64 blockWidth = 3;
|
||||
uint64 blockHeight = 4;
|
||||
uint64 blockRadius = 5;
|
||||
uint64 place = 6;
|
||||
}
|
||||
message CheckRealNameResponse{
|
||||
uint64 id =1;
|
||||
@ -91,6 +127,7 @@ message UserListInfo{
|
||||
string subNum = 14;
|
||||
string notPassRemarks = 15;
|
||||
string telNum = 16;
|
||||
string telAreaCode = 17;
|
||||
}
|
||||
message UserListRequest{
|
||||
string domain = 1;
|
||||
@ -355,11 +392,13 @@ message ListByIDsRequest {
|
||||
|
||||
message SendMsgRequest {
|
||||
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
|
||||
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
|
||||
string TelNum = 2 [json_name = "telNum"];
|
||||
//string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
|
||||
string Project = 3 [json_name = "project"];
|
||||
uint32 signNo = 4;
|
||||
uint32 mId = 5;
|
||||
string scope = 6; //标记模块
|
||||
string zone = 7; //地区 不同地区切换不同发送帐号
|
||||
}
|
||||
|
||||
message SendCustomMsgRequest {
|
||||
@ -375,9 +414,10 @@ message SendCustomMsgRequest {
|
||||
|
||||
message CheckMsgRequest {
|
||||
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
|
||||
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
|
||||
string TelNum = 2 [json_name = "telNum"];
|
||||
string Code = 3 [json_name = "code",(validator.field) = {string_not_empty: true,human_error: "70003"} ];
|
||||
string scope = 4;//标记模块
|
||||
string zone = 5; //地区 不同地区切换不同发送帐号
|
||||
}
|
||||
|
||||
message SendMsgStatusResponse {
|
||||
@ -545,11 +585,12 @@ message RegistRequest {
|
||||
|
||||
message LoginRequest {
|
||||
string Domain = 1 [json_name = "domain",(validator.field) = {string_not_empty: true,human_error: "70001"} ];
|
||||
string TelNum = 2 [json_name = "telNum",(validator.field) = {regex: "^1\\d{10}$",human_error: "70002"}];
|
||||
string TelNum = 2 [json_name = "telNum"];
|
||||
string Code = 3 [json_name = "code"];
|
||||
string Password = 4 [json_name = "password"];
|
||||
string Ip = 5 [json_name = "ip"];
|
||||
bool passCheckIp = 6 ;
|
||||
string telAreaCode = 7;
|
||||
}
|
||||
|
||||
message TokenInfo {
|
||||
|
@ -17,6 +17,27 @@ var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
func (this *SendNationMsgRequest) Validate() error {
|
||||
if this.Domain == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
|
||||
}
|
||||
if this.TelNum == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70001`))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (this *VerifySliderCaptchaResponse) Validate() error {
|
||||
return nil
|
||||
}
|
||||
func (this *VerifySliderCaptchaRequest) Validate() error {
|
||||
return nil
|
||||
}
|
||||
func (this *GenerateSliderCaptchaResponse) Validate() error {
|
||||
return nil
|
||||
}
|
||||
func (this *GenerateSliderCaptchaRequest) Validate() error {
|
||||
return nil
|
||||
}
|
||||
func (this *CheckRealNameResponse) Validate() error {
|
||||
return nil
|
||||
}
|
||||
@ -191,16 +212,10 @@ func (this *ListByIDsRequest) Validate() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _regex_SendMsgRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
|
||||
|
||||
func (this *SendMsgRequest) Validate() error {
|
||||
if this.Domain == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
|
||||
}
|
||||
if !_regex_SendMsgRequest_TelNum.MatchString(this.TelNum) {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -215,16 +230,10 @@ func (this *SendCustomMsgRequest) Validate() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _regex_CheckMsgRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
|
||||
|
||||
func (this *CheckMsgRequest) Validate() error {
|
||||
if this.Domain == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
|
||||
}
|
||||
if !_regex_CheckMsgRequest_TelNum.MatchString(this.TelNum) {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
|
||||
}
|
||||
if this.Code == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("Code", fmt.Errorf(`70003`))
|
||||
}
|
||||
@ -353,16 +362,10 @@ func (this *RequestStatus) Validate() error {
|
||||
func (this *RegistRequest) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _regex_LoginRequest_TelNum = regexp.MustCompile(`^1\d{10}$`)
|
||||
|
||||
func (this *LoginRequest) Validate() error {
|
||||
if this.Domain == "" {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("Domain", fmt.Errorf(`70001`))
|
||||
}
|
||||
if !_regex_LoginRequest_TelNum.MatchString(this.TelNum) {
|
||||
return github_com_mwitkow_go_proto_validators.FieldError("TelNum", fmt.Errorf(`70002`))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (this *TokenInfo) Validate() error {
|
||||
|
@ -64,6 +64,9 @@ type AccountClient interface {
|
||||
Register(ctx context.Context, in *RegistRequest, opts ...grpc_go.CallOption) (*RegisterResponse, common.ErrorWithAttachment)
|
||||
UserList(ctx context.Context, in *UserListRequest, opts ...grpc_go.CallOption) (*UserListResponse, common.ErrorWithAttachment)
|
||||
CheckRealName(ctx context.Context, in *CheckRealNameRequest, opts ...grpc_go.CallOption) (*CheckRealNameResponse, common.ErrorWithAttachment)
|
||||
GenerateSliderCaptcha(ctx context.Context, in *GenerateSliderCaptchaRequest, opts ...grpc_go.CallOption) (*GenerateSliderCaptchaResponse, common.ErrorWithAttachment)
|
||||
VerifySliderCaptcha(ctx context.Context, in *VerifySliderCaptchaRequest, opts ...grpc_go.CallOption) (*VerifySliderCaptchaResponse, common.ErrorWithAttachment)
|
||||
SendNationMsg(ctx context.Context, in *SendNationMsgRequest, opts ...grpc_go.CallOption) (*SendMsgStatusResponse, common.ErrorWithAttachment)
|
||||
}
|
||||
|
||||
type accountClient struct {
|
||||
@ -106,6 +109,9 @@ type AccountClientImpl struct {
|
||||
Register func(ctx context.Context, in *RegistRequest) (*RegisterResponse, error)
|
||||
UserList func(ctx context.Context, in *UserListRequest) (*UserListResponse, error)
|
||||
CheckRealName func(ctx context.Context, in *CheckRealNameRequest) (*CheckRealNameResponse, error)
|
||||
GenerateSliderCaptcha func(ctx context.Context, in *GenerateSliderCaptchaRequest) (*GenerateSliderCaptchaResponse, error)
|
||||
VerifySliderCaptcha func(ctx context.Context, in *VerifySliderCaptchaRequest) (*VerifySliderCaptchaResponse, error)
|
||||
SendNationMsg func(ctx context.Context, in *SendNationMsgRequest) (*SendMsgStatusResponse, error)
|
||||
}
|
||||
|
||||
func (c *AccountClientImpl) GetDubboStub(cc *triple.TripleConn) AccountClient {
|
||||
@ -330,6 +336,24 @@ func (c *accountClient) CheckRealName(ctx context.Context, in *CheckRealNameRequ
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/CheckRealName", in, out)
|
||||
}
|
||||
|
||||
func (c *accountClient) GenerateSliderCaptcha(ctx context.Context, in *GenerateSliderCaptchaRequest, opts ...grpc_go.CallOption) (*GenerateSliderCaptchaResponse, common.ErrorWithAttachment) {
|
||||
out := new(GenerateSliderCaptchaResponse)
|
||||
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/GenerateSliderCaptcha", in, out)
|
||||
}
|
||||
|
||||
func (c *accountClient) VerifySliderCaptcha(ctx context.Context, in *VerifySliderCaptchaRequest, opts ...grpc_go.CallOption) (*VerifySliderCaptchaResponse, common.ErrorWithAttachment) {
|
||||
out := new(VerifySliderCaptchaResponse)
|
||||
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/VerifySliderCaptcha", in, out)
|
||||
}
|
||||
|
||||
func (c *accountClient) SendNationMsg(ctx context.Context, in *SendNationMsgRequest, opts ...grpc_go.CallOption) (*SendMsgStatusResponse, common.ErrorWithAttachment) {
|
||||
out := new(SendMsgStatusResponse)
|
||||
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/SendNationMsg", in, out)
|
||||
}
|
||||
|
||||
// AccountServer is the server API for Account service.
|
||||
// All implementations must embed UnimplementedAccountServer
|
||||
// for forward compatibility
|
||||
@ -370,6 +394,9 @@ type AccountServer interface {
|
||||
Register(context.Context, *RegistRequest) (*RegisterResponse, error)
|
||||
UserList(context.Context, *UserListRequest) (*UserListResponse, error)
|
||||
CheckRealName(context.Context, *CheckRealNameRequest) (*CheckRealNameResponse, error)
|
||||
GenerateSliderCaptcha(context.Context, *GenerateSliderCaptchaRequest) (*GenerateSliderCaptchaResponse, error)
|
||||
VerifySliderCaptcha(context.Context, *VerifySliderCaptchaRequest) (*VerifySliderCaptchaResponse, error)
|
||||
SendNationMsg(context.Context, *SendNationMsgRequest) (*SendMsgStatusResponse, error)
|
||||
mustEmbedUnimplementedAccountServer()
|
||||
}
|
||||
|
||||
@ -483,6 +510,15 @@ func (UnimplementedAccountServer) UserList(context.Context, *UserListRequest) (*
|
||||
func (UnimplementedAccountServer) CheckRealName(context.Context, *CheckRealNameRequest) (*CheckRealNameResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckRealName not implemented")
|
||||
}
|
||||
func (UnimplementedAccountServer) GenerateSliderCaptcha(context.Context, *GenerateSliderCaptchaRequest) (*GenerateSliderCaptchaResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GenerateSliderCaptcha not implemented")
|
||||
}
|
||||
func (UnimplementedAccountServer) VerifySliderCaptcha(context.Context, *VerifySliderCaptchaRequest) (*VerifySliderCaptchaResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VerifySliderCaptcha not implemented")
|
||||
}
|
||||
func (UnimplementedAccountServer) SendNationMsg(context.Context, *SendNationMsgRequest) (*SendMsgStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SendNationMsg not implemented")
|
||||
}
|
||||
func (s *UnimplementedAccountServer) XXX_SetProxyImpl(impl protocol.Invoker) {
|
||||
s.proxyImpl = impl
|
||||
}
|
||||
@ -1526,6 +1562,93 @@ func _Account_CheckRealName_Handler(srv interface{}, ctx context.Context, dec fu
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Account_GenerateSliderCaptcha_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GenerateSliderCaptchaRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base := srv.(dubbo3.Dubbo3GrpcService)
|
||||
args := []interface{}{}
|
||||
args = append(args, in)
|
||||
md, _ := metadata.FromIncomingContext(ctx)
|
||||
invAttachment := make(map[string]interface{}, len(md))
|
||||
for k, v := range md {
|
||||
invAttachment[k] = v
|
||||
}
|
||||
invo := invocation.NewRPCInvocation("GenerateSliderCaptcha", args, invAttachment)
|
||||
if interceptor == nil {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
info := &grpc_go.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Account_VerifySliderCaptcha_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(VerifySliderCaptchaRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base := srv.(dubbo3.Dubbo3GrpcService)
|
||||
args := []interface{}{}
|
||||
args = append(args, in)
|
||||
md, _ := metadata.FromIncomingContext(ctx)
|
||||
invAttachment := make(map[string]interface{}, len(md))
|
||||
for k, v := range md {
|
||||
invAttachment[k] = v
|
||||
}
|
||||
invo := invocation.NewRPCInvocation("VerifySliderCaptcha", args, invAttachment)
|
||||
if interceptor == nil {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
info := &grpc_go.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Account_SendNationMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SendNationMsgRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base := srv.(dubbo3.Dubbo3GrpcService)
|
||||
args := []interface{}{}
|
||||
args = append(args, in)
|
||||
md, _ := metadata.FromIncomingContext(ctx)
|
||||
invAttachment := make(map[string]interface{}, len(md))
|
||||
for k, v := range md {
|
||||
invAttachment[k] = v
|
||||
}
|
||||
invo := invocation.NewRPCInvocation("SendNationMsg", args, invAttachment)
|
||||
if interceptor == nil {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
info := &grpc_go.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Account_ServiceDesc is the grpc_go.ServiceDesc for Account service.
|
||||
// It's only intended for direct use with grpc_go.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -1673,6 +1796,18 @@ var Account_ServiceDesc = grpc_go.ServiceDesc{
|
||||
MethodName: "CheckRealName",
|
||||
Handler: _Account_CheckRealName_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GenerateSliderCaptcha",
|
||||
Handler: _Account_GenerateSliderCaptcha_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "VerifySliderCaptcha",
|
||||
Handler: _Account_VerifySliderCaptcha_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SendNationMsg",
|
||||
Handler: _Account_SendNationMsg_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc_go.StreamDesc{},
|
||||
Metadata: "api/account/account.proto",
|
||||
|
1
clear.sh
Normal file
1
clear.sh
Normal file
@ -0,0 +1 @@
|
||||
ls api/account/*.pb.go | xargs -n1 -IX bash -c 'sed s/,omitempty// X > X.tmp && mv X{.tmp,}';
|
17
cmd/app.go
17
cmd/app.go
@ -23,9 +23,12 @@ import (
|
||||
_ "dubbo.apache.org/dubbo-go/v3/imports"
|
||||
"fmt"
|
||||
appconfig "github.com/fonchain_enterprise/micro-account/cmd/config"
|
||||
msgconfig "github.com/fonchain_enterprise/micro-account/pkg/config"
|
||||
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/cache"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/dingding"
|
||||
_ "github.com/fonchain_enterprise/micro-account/pkg/common/filter"
|
||||
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/m"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/model"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/service"
|
||||
@ -108,7 +111,21 @@ func bootstrap() (err error) {
|
||||
}
|
||||
|
||||
cache.LoadRedis(redisConfig)
|
||||
msgInfo := msgconfig.MobileConfigTemplate{
|
||||
AK: configEnv.Mobile.AK,
|
||||
SK: configEnv.Mobile.SK,
|
||||
URL: configEnv.Mobile.URL,
|
||||
}
|
||||
|
||||
aliInfo := msgconfig.AliMessage{
|
||||
AK: configEnv.AlMobile.AK,
|
||||
AS: configEnv.AlMobile.AS,
|
||||
URL: configEnv.AlMobile.URL,
|
||||
}
|
||||
|
||||
fmt.Println("飞鸽短信配置", msgInfo)
|
||||
fmt.Println("阿里短信配置", aliInfo)
|
||||
msgconfig.LoadData(msgInfo, aliInfo)
|
||||
dingding.LoadAccessToken(configEnv.Mobile.DingDingKey)
|
||||
|
||||
//logger.SetLogger()
|
||||
|
2
docs/env/dev/conf.ini
vendored
2
docs/env/dev/conf.ini
vendored
@ -15,7 +15,7 @@ DbHost = "172.16.100.30"
|
||||
DbPort = "3306"
|
||||
DbUser = "root"
|
||||
DbPassWord = "IhQmhg8HZjDmU=Ove5PnA^D"
|
||||
DbName = "fontree-account"
|
||||
DbName = "micro-account"
|
||||
|
||||
[redis]
|
||||
RedisDB = "1"
|
||||
|
2
docs/env/dev/dubbogo.yaml
vendored
2
docs/env/dev/dubbogo.yaml
vendored
@ -10,7 +10,7 @@ dubbo:
|
||||
provider:
|
||||
services:
|
||||
AccountProvider:
|
||||
interface: com.fontree.microservices.common.Account # must be compatible with grpc or dubbo-java
|
||||
interface: com.fontree.microservices.common.micro.account # must be compatible with grpc or dubbo-java
|
||||
auth: "true"
|
||||
filter: echo,metrics,token,accesslog,sign,tps,generic_service,execute,pshutdown,auth,fonValidateFilter
|
||||
params:
|
||||
|
1
go.mod
1
go.mod
@ -162,6 +162,7 @@ require (
|
||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||
github.com/multiformats/go-multihash v0.0.14 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -1089,6 +1089,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
|
383
pkg/common/utils/captcha.go
Normal file
383
pkg/common/utils/captcha.go
Normal file
@ -0,0 +1,383 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
)
|
||||
|
||||
const (
|
||||
ImgURL = "https://cdns.fontree.cn/fonchain-main/test/image/artwork/config/slidCode_%d.jpg"
|
||||
ImgPath = "./code/%d.jpg" //本地路径,暂不使用
|
||||
)
|
||||
|
||||
// 生成指定范围内的随机数
|
||||
func GetNonceByRange(start, end int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return rand.Intn(end-start+1) + start
|
||||
}
|
||||
|
||||
// 获取缓冲图片,可能是通过URL或本地路径
|
||||
func GetBufferedImage(place int) (image.Image, error) {
|
||||
nonce := GetNonceByRange(1, 10)
|
||||
var imgURL string
|
||||
|
||||
place = 0 // 注意,这边的图片现在只使用url图片
|
||||
|
||||
if place == 0 {
|
||||
imgURL = fmt.Sprintf(ImgURL, nonce)
|
||||
resp, err := http.Get(imgURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
img, _, err := image.Decode(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
} else {
|
||||
file, err := os.Open(fmt.Sprintf(ImgPath, nonce))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 调整图片大小
|
||||
func ImageResize(bufferedImage image.Image, width, height int) image.Image {
|
||||
return resize.Resize(uint(width), uint(height), bufferedImage, resize.Lanczos3)
|
||||
}
|
||||
|
||||
// CutByTemplate 根据模板裁剪图像 // 生成圆角正方形的滑块图像
|
||||
func CutByTemplate(canvasImage, blockImage draw.Image, blockWidth, blockHeight, blockX, blockY int) {
|
||||
// 创建水印图像
|
||||
waterImage := image.NewRGBA(image.Rect(0, 0, blockWidth, blockHeight))
|
||||
blockData := getRoundedSquareData(blockWidth, blockHeight)
|
||||
|
||||
// 遍历滑块区域,将滑块图案从背景中裁剪出来,并生成水印
|
||||
for i := 0; i < blockWidth; i++ {
|
||||
for j := 0; j < blockHeight; j++ {
|
||||
switch blockData[i][j] {
|
||||
case 1: // 实心区域
|
||||
blockImage.Set(i, j, canvasImage.At(blockX+i, blockY+j))
|
||||
waterImage.Set(i, j, color.Black)
|
||||
case 2: // 半透明边缘(不再需要)
|
||||
origColor := canvasImage.At(blockX+i, blockY+j)
|
||||
r, g, b, _ := origColor.RGBA()
|
||||
alpha := uint8(180)
|
||||
blockImage.Set(i, j, color.NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), alpha})
|
||||
waterImage.Set(i, j, color.NRGBA{0, 0, 0, alpha})
|
||||
case 3: // 纯白边框区域
|
||||
blockImage.Set(i, j, color.White) // 设置纯白色
|
||||
waterImage.Set(i, j, color.White)
|
||||
default: // 透明区域
|
||||
blockImage.Set(i, j, color.Transparent)
|
||||
waterImage.Set(i, j, color.Transparent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在原始画布上清除滑块区域并设置透明背景
|
||||
clearCanvasArea(canvasImage, blockData, blockX, blockY, blockWidth, blockHeight)
|
||||
}
|
||||
|
||||
// 获取带纯白边框的平滑圆角正方形的块数据
|
||||
func getRoundedSquareData(blockWidth, blockHeight int) [][]int {
|
||||
data := make([][]int, blockWidth)
|
||||
for i := range data {
|
||||
data[i] = make([]int, blockHeight)
|
||||
}
|
||||
|
||||
// 设置圆角半径为正方形边长的 20%
|
||||
cornerRadius := float64(blockWidth) * 0.2
|
||||
cornerRadiusSquared := cornerRadius * cornerRadius
|
||||
|
||||
// 设置边框厚度为 1 像素
|
||||
borderThickness := 1.0 // 纯白边框宽度为 1 像素
|
||||
borderRadiusSquared := (cornerRadius - borderThickness) * (cornerRadius - borderThickness)
|
||||
|
||||
for i := 0; i < blockWidth; i++ {
|
||||
for j := 0; j < blockHeight; j++ {
|
||||
// 处理四个角的圆角
|
||||
if (i < int(cornerRadius) && j < int(cornerRadius)) || // 左上角
|
||||
(i >= blockWidth-int(cornerRadius) && j < int(cornerRadius)) || // 右上角
|
||||
(i < int(cornerRadius) && j >= blockHeight-int(cornerRadius)) || // 左下角
|
||||
(i >= blockWidth-int(cornerRadius) && j >= blockHeight-int(cornerRadius)) { // 右下角
|
||||
|
||||
// 计算距离的平方,判断是否在圆角内
|
||||
var dx, dy float64
|
||||
if i < int(cornerRadius) {
|
||||
dx = float64(i) - cornerRadius
|
||||
} else {
|
||||
dx = float64(i) - float64(blockWidth) + cornerRadius
|
||||
}
|
||||
if j < int(cornerRadius) {
|
||||
dy = float64(j) - cornerRadius
|
||||
} else {
|
||||
dy = float64(j) - float64(blockHeight) + cornerRadius
|
||||
}
|
||||
|
||||
distanceSquared := dx*dx + dy*dy
|
||||
if distanceSquared > cornerRadiusSquared {
|
||||
data[i][j] = 0 // 圆角外部区域
|
||||
} else if distanceSquared > borderRadiusSquared {
|
||||
data[i][j] = 3 // 纯白边框区域
|
||||
} else {
|
||||
data[i][j] = 1 // 实心区域
|
||||
}
|
||||
} else {
|
||||
// 非圆角区域
|
||||
if (i < int(borderThickness) || i >= blockWidth-int(borderThickness)) || // 左右边缘
|
||||
(j < int(borderThickness) || j >= blockHeight-int(borderThickness)) { // 上下边缘
|
||||
data[i][j] = 3 // 纯白边框区域
|
||||
} else {
|
||||
data[i][j] = 1 // 实心区域
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// 随机生成一个不重叠的滑块区域
|
||||
func generateNonOverlappingArea(canvasWidth, canvasHeight, blockX, blockY, blockWidth, blockHeight int) (int, int) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var newX, newY int
|
||||
|
||||
for {
|
||||
// 随机生成新区域的位置
|
||||
newX = rand.Intn(canvasWidth - blockWidth)
|
||||
newY = rand.Intn(canvasHeight - blockHeight)
|
||||
|
||||
// 检查新区域是否与原始区域重叠
|
||||
if (newX+blockWidth <= blockX || newX >= blockX+blockWidth) &&
|
||||
(newY+blockHeight <= blockY || newY >= blockY+blockHeight) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return newX, newY
|
||||
}
|
||||
|
||||
// 将滑块区域设为半透明,并生成不重叠的额外区域
|
||||
func clearCanvasArea(canvasImage draw.Image, blockData [][]int, blockX, blockY, blockWidth, blockHeight int) {
|
||||
alpha := uint8(128) // 50% 透明度
|
||||
|
||||
// 设置原始滑块区域为半透明
|
||||
for i := 0; i < blockWidth; i++ {
|
||||
for j := 0; j < blockHeight; j++ {
|
||||
if blockData[i][j] > 0 {
|
||||
// 获取原始像素的 RGB 值,并统一设置 Alpha 通道
|
||||
originalColor := canvasImage.At(blockX+i, blockY+j)
|
||||
r, g, b, _ := originalColor.RGBA()
|
||||
|
||||
// 设置新的颜色并固定透明度
|
||||
semiTransparentColor := color.NRGBA{
|
||||
R: uint8(r >> 8),
|
||||
G: uint8(g >> 8),
|
||||
B: uint8(b >> 8),
|
||||
A: alpha, // 固定透明度
|
||||
}
|
||||
|
||||
// 应用半透明效果
|
||||
canvasImage.Set(blockX+i, blockY+j, semiTransparentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成不重叠的新区域位置
|
||||
canvasBounds := canvasImage.Bounds()
|
||||
newBlockX, newBlockY := generateNonOverlappingArea(canvasBounds.Max.X, canvasBounds.Max.Y, blockX, blockY, blockWidth, blockHeight)
|
||||
|
||||
// 可以在新区域执行与原始区域相同的操作,或根据需求自定义
|
||||
for i := 0; i < blockWidth; i++ {
|
||||
for j := 0; j < blockHeight; j++ {
|
||||
if blockData[i][j] > 0 {
|
||||
// 获取原始像素的 RGB 值,并统一设置 Alpha 通道
|
||||
originalColor := canvasImage.At(newBlockX+i, newBlockY+j)
|
||||
r, g, b, _ := originalColor.RGBA()
|
||||
|
||||
// 设置新的颜色并固定透明度
|
||||
semiTransparentColor := color.NRGBA{
|
||||
R: uint8(r >> 8),
|
||||
G: uint8(g >> 8),
|
||||
B: uint8(b >> 8),
|
||||
A: alpha, // 固定透明度
|
||||
}
|
||||
|
||||
// 应用半透明效果
|
||||
canvasImage.Set(newBlockX+i, newBlockY+j, semiTransparentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// 清除画布上的滑块区域,使其为黑色背景
|
||||
//func clearCanvasArea(canvasImage draw.Image, blockData [][]int, blockX, blockY, blockWidth, blockHeight int) {
|
||||
// alpha := uint8(128) // 50% 透明度
|
||||
//
|
||||
// for i := 0; i < blockWidth; i++ {
|
||||
// for j := 0; j < blockHeight; j++ {
|
||||
// if blockData[i][j] > 0 {
|
||||
// // 获取原始像素的 RGB 值,并统一设置 Alpha 通道
|
||||
// originalColor := canvasImage.At(blockX+i, blockY+j)
|
||||
// r, g, b, _ := originalColor.RGBA()
|
||||
//
|
||||
// // 设置新的颜色并固定透明度
|
||||
// semiTransparentColor := color.NRGBA{
|
||||
// R: uint8(r >> 8),
|
||||
// G: uint8(g >> 8),
|
||||
// B: uint8(b >> 8),
|
||||
// A: alpha, // 固定透明度
|
||||
// }
|
||||
//
|
||||
// // 应用半透明效果
|
||||
// canvasImage.Set(blockX+i, blockY+j, semiTransparentColor)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//// 根据模板裁剪图像 // 生成拼图类型的滑块图像 有需要打开
|
||||
//func CutByTemplate(canvasImage, blockImage draw.Image, blockWidth, blockHeight, blockRadius, blockX, blockY int) (faceY int) {
|
||||
// waterImage := image.NewRGBA(image.Rect(0, 0, blockWidth, blockHeight))
|
||||
// var blockData [][]int
|
||||
// blockData, faceY = getBlockData(blockWidth, blockHeight, blockRadius, blockY)
|
||||
//
|
||||
// for i := 0; i < blockWidth; i++ {
|
||||
// for j := 0; j < blockHeight; j++ {
|
||||
// if blockData[i][j] == 1 {
|
||||
// // 设置水印背景为黑色
|
||||
// waterImage.Set(i, j, color.Black)
|
||||
// // 从原始图像中获取像素
|
||||
// blockImage.Set(i, j, canvasImage.At(blockX+i, blockY+j))
|
||||
//
|
||||
// // 设置轮廓为白色
|
||||
// if (i+1 < blockWidth && blockData[i+1][j] == 0) ||
|
||||
// (j+1 < blockHeight && blockData[i][j+1] == 0) ||
|
||||
// (i-1 >= 0 && blockData[i-1][j] == 0) ||
|
||||
// (j-1 >= 0 && blockData[i][j-1] == 0) {
|
||||
// blockImage.Set(i, j, color.White)
|
||||
// waterImage.Set(i, j, color.White)
|
||||
// }
|
||||
// } else {
|
||||
// // 背景设为透明
|
||||
// blockImage.Set(i, j, color.Transparent)
|
||||
// waterImage.Set(i, j, color.Transparent)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// addBlockWatermark(canvasImage, waterImage, blockX, blockY)
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// 获取块数据,用以确定块的形状
|
||||
//func getBlockData(blockWidth, blockHeight, blockRadius, blockY int) (blockData [][]int, faceY int) {
|
||||
// data := make([][]int, blockWidth)
|
||||
// for i := range data {
|
||||
// data[i] = make([]int, blockHeight)
|
||||
// }
|
||||
// rand.Seed(time.Now().UnixNano())
|
||||
//
|
||||
// // 确定两个随机方向和凸/凹形状
|
||||
// face1, face2 := rand.Intn(4), rand.Intn(4)
|
||||
// for face1 == face2 {
|
||||
// face2 = rand.Intn(4)
|
||||
// }
|
||||
//
|
||||
// shape := rand.Intn(2) // 0: 凸,1: 凹
|
||||
// circle1 := getCircleCoords(face1, blockWidth, blockHeight, blockRadius)
|
||||
// circle2 := getCircleCoords(face2, blockWidth, blockHeight, blockRadius)
|
||||
//
|
||||
// if (face1 == 2 || face2 == 2) && shape == 1 {
|
||||
// faceY = blockY - blockRadius
|
||||
// } else {
|
||||
// faceY = blockY
|
||||
// }
|
||||
// // 计算轮廓
|
||||
// radiusSquared := float64(blockRadius * blockRadius)
|
||||
// for i := 0; i < blockWidth; i++ {
|
||||
// for j := 0; j < blockHeight; j++ {
|
||||
// if i >= blockRadius && i < blockWidth-blockRadius && j >= blockRadius && j < blockHeight-blockRadius {
|
||||
// data[i][j] = 1
|
||||
// }
|
||||
// if circle1 != nil && math.Pow(float64(i-circle1[0]), 2)+math.Pow(float64(j-circle1[1]), 2) <= radiusSquared {
|
||||
// data[i][j] = shape
|
||||
// }
|
||||
// if circle2 != nil && math.Pow(float64(i-circle2[0]), 2)+math.Pow(float64(j-circle2[1]), 2) <= radiusSquared {
|
||||
// data[i][j] = shape
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return data, faceY
|
||||
//}
|
||||
//
|
||||
//// 根据方向获取圆心坐标
|
||||
//func getCircleCoords(face, blockWidth, blockHeight, blockRadius int) []int {
|
||||
// switch face {
|
||||
// case 0:
|
||||
// return []int{blockWidth / 2, blockRadius} // 上
|
||||
// case 1:
|
||||
// return []int{blockRadius, blockHeight / 2} // 左
|
||||
// case 2:
|
||||
// return []int{blockWidth / 2, blockHeight - blockRadius - 1} // 下
|
||||
// case 3:
|
||||
// return []int{blockWidth - blockRadius - 1, blockHeight / 2} // 右
|
||||
// default:
|
||||
// return nil
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// 在画布图像上添加水印
|
||||
//func addBlockWatermark(canvasImage, waterImage draw.Image, blockX, blockY int) {
|
||||
// for i := 0; i < waterImage.Bounds().Dx(); i++ {
|
||||
// for j := 0; j < waterImage.Bounds().Dy(); j++ {
|
||||
// if _, _, _, alpha := waterImage.At(i, j).RGBA(); alpha > 0 {
|
||||
// canvasImage.Set(blockX+i, blockY+j, waterImage.At(i, j))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// 将图像转换为Base64编码
|
||||
func ToBase64(img image.Image, format string) string {
|
||||
buf := new(bytes.Buffer)
|
||||
switch format {
|
||||
case "png":
|
||||
png.Encode(buf, img)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||
}
|
||||
|
||||
// 计算绝对值
|
||||
func Abs(a int) int {
|
||||
if a < 0 {
|
||||
return -a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// 将字符串转换为整数
|
||||
func ParseInt(s string) int {
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
74
pkg/common/verifica/nation_mobile.go
Normal file
74
pkg/common/verifica/nation_mobile.go
Normal file
@ -0,0 +1,74 @@
|
||||
package verifica
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type nationAccount struct {
|
||||
ak string
|
||||
sk string
|
||||
}
|
||||
|
||||
type NationMsg struct {
|
||||
Apikey string `json:"apikey"`
|
||||
Secret string `json:"secret"`
|
||||
Content string `json:"content"`
|
||||
Mobile string `json:"mobile"`
|
||||
TemplateId int `json:"template_id"`
|
||||
SendTime int64 `json:"send_time"`
|
||||
}
|
||||
|
||||
const (
|
||||
sendNationMsgUrl = "https://api.4321.sh/inter/send"
|
||||
nationMsgTemplateId = 107570 //[$$]您此次验证码为$$,60秒内有效,请您尽快验证!
|
||||
accessKey = "I1185562576"
|
||||
secretKey = "1185566b86c739e71"
|
||||
)
|
||||
|
||||
var nationAccountObj *nationAccount
|
||||
|
||||
func loadEnv(ak, sk string) {
|
||||
nationAccountObj = &nationAccount{
|
||||
ak: ak,
|
||||
sk: sk,
|
||||
}
|
||||
}
|
||||
|
||||
func SendNationMsg(telNum, content string, templateId int) error {
|
||||
if templateId == 0 {
|
||||
templateId = nationMsgTemplateId
|
||||
}
|
||||
fmt.Print("content:", content)
|
||||
loadEnv(accessKey, secretKey)
|
||||
//设置飞鸽发送短信需要的参数
|
||||
msg := NationMsg{
|
||||
Apikey: nationAccountObj.ak,
|
||||
Secret: nationAccountObj.sk,
|
||||
Content: content,
|
||||
Mobile: telNum,
|
||||
TemplateId: templateId,
|
||||
SendTime: time.Now().Unix(),
|
||||
}
|
||||
|
||||
//转json
|
||||
dataJsonBytes, _ := json.Marshal(msg)
|
||||
data := strings.NewReader(string(dataJsonBytes))
|
||||
fmt.Println(string(dataJsonBytes))
|
||||
|
||||
resp, err := http.Post(sendNationMsgUrl, "application/json", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bodyText, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", bodyText)
|
||||
|
||||
return nil
|
||||
}
|
@ -61,3 +61,4 @@ const (
|
||||
MailRootUserName = "postmaster@fontree.cn"
|
||||
MailRootPaw = "Zaq12wsx"
|
||||
)
|
||||
const AllowDeviation = 5
|
||||
|
59
pkg/model/captcha.go
Normal file
59
pkg/model/captcha.go
Normal file
@ -0,0 +1,59 @@
|
||||
package model
|
||||
|
||||
import "errors"
|
||||
|
||||
// Captcha 结构体定义了验证码的属性
|
||||
type Captcha struct {
|
||||
NonceStr string `json:"nonceStr"` // 随机字符串,用于唯一标识验证码
|
||||
CanvasSrc string `json:"canvasSrc"` // 画布图像的Base64编码字符串
|
||||
BlockSrc string `json:"blockSrc"` // 块图像的Base64编码字符串
|
||||
BlockX int `json:"blockX"` // 块图像在画布上的X轴位置
|
||||
BlockY int `json:"blockY"` // 块图像在画布上的Y轴位置
|
||||
CanvasWidth int `json:"canvasWidth"` // 画布的宽度
|
||||
CanvasHeight int `json:"canvasHeight"` // 画布的高度
|
||||
BlockWidth int `json:"blockWidth"` // 块图像的宽度
|
||||
BlockHeight int `json:"blockHeight"` // 块图像的高度
|
||||
BlockRadius int `json:"blockRadius"` // 块图像的圆角半径
|
||||
Place int `json:"place"` // 图像来源标识,0表示URL下载,1表示本地文件
|
||||
}
|
||||
|
||||
// Verification 结构体定义了验证验证码的属性
|
||||
type Verification struct {
|
||||
NonceStr string `json:"nonceStr"` // 随机字符串,用于唯一标识验证码
|
||||
BlockX string `json:"blockX"` // 画布图像的Base64编码字符串
|
||||
}
|
||||
|
||||
// 检查并设置验证码的默认参数
|
||||
func CheckCaptcha(captcha *Captcha) (err error) {
|
||||
|
||||
// 参数值不可以小于15
|
||||
if captcha.CanvasWidth < 41 || captcha.CanvasHeight < 26 {
|
||||
captcha.CanvasWidth = 320
|
||||
captcha.CanvasHeight = 155
|
||||
}
|
||||
|
||||
if captcha.BlockWidth < 15 || captcha.BlockHeight < 15 {
|
||||
captcha.BlockWidth = 65
|
||||
captcha.BlockHeight = 55
|
||||
}
|
||||
|
||||
if captcha.BlockRadius < 5 {
|
||||
captcha.BlockRadius = 9
|
||||
}
|
||||
|
||||
if captcha.Place == 0 {
|
||||
captcha.Place = 0
|
||||
}
|
||||
|
||||
if (captcha.CanvasWidth-10)/2 <= captcha.BlockWidth {
|
||||
err = errors.New("请输入符合规范的像素值")
|
||||
return
|
||||
}
|
||||
|
||||
if captcha.CanvasHeight-captcha.BlockHeight <= 10 {
|
||||
err = errors.New("请输入符合规范的像素值")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -21,6 +21,7 @@ func migration() {
|
||||
AddTable(&LoginLog{})
|
||||
AddTable(&RealName{})
|
||||
AddTable(&User{})
|
||||
AddTable(&RefreshToken{})
|
||||
}
|
||||
|
||||
// 数据迁移
|
||||
|
@ -10,7 +10,7 @@ type RealName struct {
|
||||
ID uint `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"`
|
||||
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11)"`
|
||||
Name string `gorm:"column:name;comment:姓名" json:"name"`
|
||||
Sex int `gorm:"column:sex;comment:性别:1男 2女" json:"sex"`
|
||||
Nationality string `gorm:"column:nationality;comment:国籍" json:"nationality"`
|
||||
|
@ -45,7 +45,7 @@ type User struct {
|
||||
Status int `gorm:"column:status;comment:状态 1:未实名 2:审核中 3:审核失败 4:审核通过" json:"status"`
|
||||
RegistrationTime string `gorm:"column:registration_time;comment:注册时间" json:"registrationTime"`
|
||||
AuditTime string `gorm:"column:audit_time;comment:审核时间" json:"auditTime"`
|
||||
RealNameID uint
|
||||
RealNameID *uint
|
||||
RealName *RealName `gorm:"foreignKey:RealNameID" json:"RealName"`
|
||||
PasswordDigest string
|
||||
NotPassRemarks string `gorm:"column:not_pass_remarks;comment:不通过备注" json:"notPassRemarks"`
|
||||
|
@ -69,23 +69,38 @@ func BuildUserList(user []*model.User) []*account.UserListInfo {
|
||||
}
|
||||
var userList []*account.UserListInfo
|
||||
for _, i := range user {
|
||||
realName := i.RealName
|
||||
if realName == nil {
|
||||
realName = &model.RealName{
|
||||
Name: "",
|
||||
Sex: 0,
|
||||
Nationality: "",
|
||||
DocumentType: 0,
|
||||
CertificatePicture: "",
|
||||
Validity: "",
|
||||
PlaceOfResidence: "",
|
||||
GroupPhoto: "",
|
||||
Attachment: "",
|
||||
}
|
||||
}
|
||||
userList = append(userList, &account.UserListInfo{
|
||||
Id: uint64(i.ID),
|
||||
Status: int32(i.Status),
|
||||
Name: i.RealName.Name,
|
||||
Sex: int32(i.RealName.Sex),
|
||||
Nationality: i.RealName.Nationality,
|
||||
DocumentType: int32(i.RealName.DocumentType),
|
||||
CertificatePicture: i.RealName.CertificatePicture,
|
||||
Validity: i.RealName.Validity,
|
||||
PlaceOfResidence: i.RealName.PlaceOfResidence,
|
||||
GroupPhoto: i.RealName.GroupPhoto,
|
||||
Attachment: i.RealName.Attachment,
|
||||
Name: realName.Name,
|
||||
Sex: int32(realName.Sex),
|
||||
Nationality: realName.Nationality,
|
||||
DocumentType: int32(realName.DocumentType),
|
||||
CertificatePicture: realName.CertificatePicture,
|
||||
Validity: realName.Validity,
|
||||
PlaceOfResidence: realName.PlaceOfResidence,
|
||||
GroupPhoto: realName.GroupPhoto,
|
||||
Attachment: realName.Attachment,
|
||||
RegistrationTime: i.RegistrationTime,
|
||||
AuditTime: i.AuditTime,
|
||||
SubNum: i.SubNum,
|
||||
NotPassRemarks: i.NotPassRemarks,
|
||||
TelNum: i.TelNum,
|
||||
TelAreaCode: i.TelAreaCode,
|
||||
})
|
||||
}
|
||||
return userList
|
||||
|
@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"dubbo.apache.org/dubbo-go/v3/common/logger"
|
||||
_ "dubbo.apache.org/dubbo-go/v3/imports"
|
||||
"errors"
|
||||
@ -12,15 +13,20 @@ import (
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/jwt"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/page"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/redis_key"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/utils"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/common/verifica"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/domain"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/m"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/model"
|
||||
"github.com/fonchain_enterprise/micro-account/pkg/serializer"
|
||||
"github.com/fonchain_enterprise/utils/mobile"
|
||||
"github.com/go-redis/redis"
|
||||
uuid2 "github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"image"
|
||||
"log"
|
||||
"math"
|
||||
rand2 "math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -93,7 +99,7 @@ func (a *AccountProvider) Login(ctx context.Context, in *account.LoginRequest) (
|
||||
|
||||
fmt.Println("---------------add1---", time.Now().Sub(timeNow))
|
||||
if in.Code != "" {
|
||||
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelNum)) // 登陆检测
|
||||
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelAreaCode+in.TelNum)) // 登陆检测
|
||||
code := str.Val()
|
||||
if code != in.Code {
|
||||
return nil, errors.New(m.ERRORCODE)
|
||||
@ -256,15 +262,15 @@ func (a *AccountProvider) OnlyCheckMsg(_ context.Context, in *account.CheckMsgRe
|
||||
func (a *AccountProvider) SendMsg(_ context.Context, in *account.SendMsgRequest) (*account.SendMsgStatusResponse, error) {
|
||||
response := &account.SendMsgStatusResponse{}
|
||||
|
||||
var user *model.User
|
||||
//var user *model.User
|
||||
|
||||
if domain.InBlockList(in.Domain, in.TelNum) {
|
||||
return nil, errors.New(m.Black_Mobile_Sended)
|
||||
}
|
||||
|
||||
if err := model.DB.Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&user).Error; err != nil {
|
||||
return nil, errors.New(m.Not_Found)
|
||||
}
|
||||
//if err := model.DB.Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&user).Error; err != nil {
|
||||
// return nil, errors.New(m.Not_Found)
|
||||
//}
|
||||
|
||||
//此处不再校验验证码有效期
|
||||
//校验(1-是否已经发送 2-是否今日发送超过指定数量)
|
||||
@ -375,7 +381,7 @@ func (a *AccountProvider) RealName(_ context.Context, in *account.RealNameReques
|
||||
return &account.RealNameResponse{Status: m.FAILED}, errors.New("实名审核中,请勿重复提交")
|
||||
}
|
||||
// 检查用户是否已关联实名信息
|
||||
if existingUser.RealNameID == 0 {
|
||||
if existingUser.RealNameID == nil {
|
||||
// 如果没有找到实名信息,创建一个新的 RealName 记录
|
||||
newRealName := model.RealName{
|
||||
Name: in.Name,
|
||||
@ -393,16 +399,18 @@ func (a *AccountProvider) RealName(_ context.Context, in *account.RealNameReques
|
||||
return &account.RealNameResponse{Status: m.FAILED}, err
|
||||
}
|
||||
// 更新用户的实名信息 ID
|
||||
existingUser.RealNameID = newRealName.ID
|
||||
existingUser.RealNameID = &newRealName.ID
|
||||
existingUser.Status = m.UnderReview // 审核中状态
|
||||
if err := model.DB.Save(&existingUser).Error; err != nil {
|
||||
return &account.RealNameResponse{Status: m.FAILED}, err
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
return &account.RealNameResponse{Status: m.SUCCESS}, nil
|
||||
}
|
||||
// 如果已存在实名信息,更新该信息
|
||||
updateData := map[string]interface{}{
|
||||
"status": m.UnderReview, // 审核中状态
|
||||
//"status": m.UnderReview, // 审核中状态
|
||||
"name": in.Name,
|
||||
"sex": in.Sex,
|
||||
"nationality": in.Nationality,
|
||||
@ -418,7 +426,9 @@ func (a *AccountProvider) RealName(_ context.Context, in *account.RealNameReques
|
||||
if err := model.DB.First(&existingRealName, "id = ?", existingUser.RealNameID).Error; err != nil {
|
||||
return &account.RealNameResponse{Status: m.FAILED}, err
|
||||
}
|
||||
|
||||
if err := model.DB.Model(&existingUser).Update("status", m.UnderReview).Error; err != nil {
|
||||
return &account.RealNameResponse{Status: m.FAILED}, err
|
||||
}
|
||||
if err := model.DB.Model(&existingRealName).Updates(updateData).Error; err != nil {
|
||||
return &account.RealNameResponse{Status: m.FAILED}, err
|
||||
}
|
||||
@ -465,7 +475,7 @@ func (a *AccountProvider) Register(_ context.Context, in *account.RegistRequest)
|
||||
if in.Code == "" {
|
||||
return &account.RegisterResponse{Status: m.Unknown}, errors.New(m.Mobile_Wrong_Code)
|
||||
}
|
||||
if err := domain.CheckRegisterCode(in.Domain, in.TelNum, in.Code); err != nil {
|
||||
if err := domain.CheckRegisterCode(in.Domain, in.TelAreaCode+in.TelNum, in.Code); err != nil {
|
||||
return &account.RegisterResponse{Status: m.Unknown}, errors.New(m.Mobile_Code_Wrong)
|
||||
}
|
||||
// 手机号是否已注册
|
||||
@ -477,23 +487,23 @@ func (a *AccountProvider) Register(_ context.Context, in *account.RegistRequest)
|
||||
// 查询错误
|
||||
return &account.RegisterResponse{Status: m.Unknown}, err
|
||||
}
|
||||
var subNum string
|
||||
if err := model.DB.Model(&model.User{}).Select("MAX(SUBSTRING(SubNum, 3, 6))").Row().Scan(&subNum); err != nil {
|
||||
var subNum sql.NullString
|
||||
if err := model.DB.Model(&model.User{}).Select("MAX(SUBSTRING(sub_num, 3, 6))").Row().Scan(&subNum); err != nil {
|
||||
return &account.RegisterResponse{Status: m.Unknown}, err
|
||||
}
|
||||
var newNum int
|
||||
if subNum == "" {
|
||||
if !subNum.Valid || subNum.String == "" {
|
||||
// 如果没有用户,起始编号为 FE00001
|
||||
newNum = 1
|
||||
} else {
|
||||
// 递增现有编号
|
||||
parsedNum, err := strconv.Atoi(subNum)
|
||||
parsedNum, err := strconv.Atoi(subNum.String)
|
||||
if err != nil {
|
||||
return &account.RegisterResponse{Status: m.Unknown}, err
|
||||
}
|
||||
newNum = parsedNum + 1
|
||||
}
|
||||
subNum = fmt.Sprintf("FE%05d", newNum)
|
||||
subNum.String = fmt.Sprintf("FE%05d", newNum)
|
||||
//数据库中创建该用户记录
|
||||
|
||||
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||
@ -506,7 +516,8 @@ func (a *AccountProvider) Register(_ context.Context, in *account.RegistRequest)
|
||||
Status: m.Unnamed,
|
||||
TelAreaCode: in.TelAreaCode,
|
||||
RegistrationTime: time.Now().In(loc).Format("2006-01-02 15:04:05"),
|
||||
SubNum: subNum,
|
||||
SubNum: subNum.String,
|
||||
RealNameID: nil,
|
||||
}
|
||||
if err = model.DB.Create(&user).Error; err != nil {
|
||||
return &account.RegisterResponse{Status: 0}, err
|
||||
@ -581,18 +592,32 @@ func (a *AccountProvider) Info(ctx context.Context, in *account.InfoRequest) (*a
|
||||
logger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
realName := user.RealName
|
||||
if realName == nil {
|
||||
realName = &model.RealName{
|
||||
Name: "",
|
||||
Sex: 0,
|
||||
Nationality: "",
|
||||
DocumentType: 0,
|
||||
CertificatePicture: "",
|
||||
Validity: "",
|
||||
PlaceOfResidence: "",
|
||||
GroupPhoto: "",
|
||||
Attachment: "",
|
||||
}
|
||||
}
|
||||
response := &account.UserInfoResponse{
|
||||
Id: uint64(user.ID),
|
||||
Status: int32(user.Status),
|
||||
Name: user.RealName.Name,
|
||||
Sex: int32(user.RealName.Sex),
|
||||
Nationality: user.RealName.Nationality,
|
||||
DocumentType: int32(user.RealName.DocumentType),
|
||||
CertificatePicture: user.RealName.CertificatePicture,
|
||||
Validity: user.RealName.Validity,
|
||||
PlaceOfResidence: user.RealName.PlaceOfResidence,
|
||||
GroupPhoto: user.RealName.GroupPhoto,
|
||||
Attachment: user.RealName.Attachment,
|
||||
Name: realName.Name,
|
||||
Sex: int32(realName.Sex),
|
||||
Nationality: realName.Nationality,
|
||||
DocumentType: int32(realName.DocumentType),
|
||||
CertificatePicture: realName.CertificatePicture,
|
||||
Validity: realName.Validity,
|
||||
PlaceOfResidence: realName.PlaceOfResidence,
|
||||
GroupPhoto: realName.GroupPhoto,
|
||||
Attachment: realName.Attachment,
|
||||
SubNum: user.SubNum,
|
||||
NotPassRemarks: user.NotPassRemarks,
|
||||
}
|
||||
@ -603,6 +628,9 @@ func (a *AccountProvider) UserList(ctx context.Context, in *account.UserListRequ
|
||||
var count int64
|
||||
var users []*model.User
|
||||
modelObj := model.DB.Model(&model.User{}).Preload("RealName")
|
||||
if in.Domain != "" {
|
||||
modelObj.Where("domain = ? ", in.Domain)
|
||||
}
|
||||
if in.SubNum != "" {
|
||||
modelObj.Where("sub_num like ? ", "%"+in.SubNum+"%")
|
||||
}
|
||||
@ -635,6 +663,137 @@ func (a *AccountProvider) UserList(ctx context.Context, in *account.UserListRequ
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// 艺术商城,发送国际短信验证码
|
||||
func (a *AccountProvider) SendNationMsg(_ context.Context, in *account.SendNationMsgRequest) (*account.SendMsgStatusResponse, error) {
|
||||
response := &account.SendMsgStatusResponse{}
|
||||
// var user *model.User
|
||||
|
||||
if domain.InBlockList(in.Domain, in.TelNum) {
|
||||
return nil, errors.New(m.Black_Mobile_Sended)
|
||||
}
|
||||
|
||||
// if err := model.DB.Where(&model.User{TelNum: in.TelNum, Domain: &in.Domain}).First(&user).Error; err != nil {
|
||||
// return nil, errors.New(m.Not_Found)
|
||||
// }
|
||||
|
||||
//此处不再校验验证码有效期
|
||||
//校验(1-是否已经发送 2-是否今日发送超过指定数量)
|
||||
/*
|
||||
str := cache.RedisClient.Get(redis_key.GetAccountKey(in.Domain, in.TelNum)) // 发送验证码
|
||||
|
||||
if str.Val() != "" {
|
||||
return nil, errors.New(m.Mobile_Sended)
|
||||
}
|
||||
*/
|
||||
|
||||
code := mobile.RandCode()
|
||||
|
||||
//是否存活 (1分钟冷却) (1-是否已经发送 2-是否今日发送超过指定数量) 55秒
|
||||
if err := domain.CodeLive(in.Domain, in.TelNum); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//今日是否达到上限
|
||||
if err := domain.CheckMsg(redis_key.GetAccountKeyCountToday(in.Domain, in.TelNum)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//执行发送 并且记录code
|
||||
err := verifica.SendNationMsg(in.TelNum, fmt.Sprintf("艺术商城||%s", code), 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = domain.SetRecordTelMsgCode(in.Domain, in.TelNum, code)
|
||||
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
|
||||
}
|
||||
func (a *AccountProvider) GenerateSliderCaptcha(_ context.Context, in *account.GenerateSliderCaptchaRequest) (*account.GenerateSliderCaptchaResponse, error) {
|
||||
|
||||
captcha := &model.Captcha{
|
||||
CanvasWidth: int(in.CanvasWidth),
|
||||
CanvasHeight: int(in.CanvasHeight),
|
||||
BlockWidth: int(in.BlockWidth),
|
||||
BlockHeight: int(in.BlockHeight),
|
||||
Place: int(in.Place),
|
||||
}
|
||||
|
||||
err := model.CheckCaptcha(captcha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvasWidth := captcha.CanvasWidth
|
||||
canvasHeight := captcha.CanvasHeight
|
||||
blockWidth := captcha.BlockWidth
|
||||
blockHeight := captcha.BlockHeight
|
||||
//blockRadius := captcha.BlockRadius
|
||||
place := captcha.Place
|
||||
|
||||
img, _ := utils.GetBufferedImage(place)
|
||||
canvasImage := utils.ImageResize(img, canvasWidth, canvasHeight).(*image.RGBA)
|
||||
blockX := utils.GetNonceByRange(blockWidth, canvasWidth-blockWidth-10)
|
||||
blockY := utils.GetNonceByRange(10, canvasHeight-blockHeight+1)
|
||||
blockImage := image.NewRGBA(image.Rect(0, 0, blockWidth, blockHeight))
|
||||
|
||||
utils.CutByTemplate(canvasImage, blockImage, blockWidth, blockHeight, blockX, blockY)
|
||||
fmt.Println("1---", 0)
|
||||
fmt.Println("2---", blockY)
|
||||
fmt.Println("2---", blockX)
|
||||
|
||||
// 生成UUID
|
||||
nonceStr := fmt.Sprintf("%x", rand2.New(rand2.NewSource(time.Now().UnixNano())).Uint64())
|
||||
|
||||
// 保存X轴像素
|
||||
cache.RedisClient.Set("imageCode:"+nonceStr, blockX, 15*time.Minute)
|
||||
|
||||
resp := &account.GenerateSliderCaptchaResponse{
|
||||
NonceStr: nonceStr,
|
||||
CanvasSrc: utils.ToBase64(canvasImage, "png"),
|
||||
BlockSrc: utils.ToBase64(blockImage, "png"),
|
||||
BlockY: uint64(blockY),
|
||||
FaceY: 0,
|
||||
//BlockX: uint64(blockX),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (a *AccountProvider) VerifySliderCaptcha(_ context.Context, in *account.VerifySliderCaptchaRequest) (*account.VerifySliderCaptchaResponse, error) {
|
||||
|
||||
resp := &account.VerifySliderCaptchaResponse{}
|
||||
|
||||
// 检查图像验证码
|
||||
text, err := cache.RedisClient.Get("imageCode:" + in.NonceStr).Result()
|
||||
if err == redis.Nil {
|
||||
err = errors.New("验证码已失效")
|
||||
return resp, err
|
||||
} else if err != nil {
|
||||
err = errors.New("服务器错误")
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if utils.Abs(utils.ParseInt(text)-int(math.Round(float64(in.BlockX)))) > m.AllowDeviation {
|
||||
err = errors.New("验证失败,请控制拼图对齐缺口")
|
||||
return resp, err
|
||||
}
|
||||
|
||||
err = cache.RedisClient.Set("SliderStatus:"+in.NonceStr, "unused", 15*time.Minute).Err()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
resp.NonceStr = in.NonceStr
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (a *AccountProvider) DecryptJwt(_ context.Context, in *account.DecryptJwtRequest) (*account.DecryptJwtResponse, error) {
|
||||
|
||||
//默认在线
|
||||
|
Loading…
Reference in New Issue
Block a user