This commit is contained in:
桀尼龟 2025-02-21 16:57:10 +08:00
parent 3cff7a380f
commit 63d89c7a12
19 changed files with 3609 additions and 2183 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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 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 {

View File

@ -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 {

View File

@ -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
View File

@ -0,0 +1 @@
ls api/account/*.pb.go | xargs -n1 -IX bash -c 'sed s/,omitempty// X > X.tmp && mv X{.tmp,}';

View File

@ -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()

View File

@ -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"

View File

@ -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
View File

@ -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
View File

@ -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
View 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
}

View 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
}

View File

@ -61,3 +61,4 @@ const (
MailRootUserName = "postmaster@fontree.cn"
MailRootPaw = "Zaq12wsx"
)
const AllowDeviation = 5

59
pkg/model/captcha.go Normal file
View 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
}

View File

@ -21,6 +21,7 @@ func migration() {
AddTable(&LoginLog{})
AddTable(&RealName{})
AddTable(&User{})
AddTable(&RefreshToken{})
}
// 数据迁移

View File

@ -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"`

View File

@ -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"`

View File

@ -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

View File

@ -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) {
//默认在线