feat: aliyun sms
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
deploy/mysql/data
|
deploy/mysql/data
|
||||||
deploy/redis/data
|
deploy/redis/data
|
||||||
|
deploy/rnacos/data
|
||||||
|
|
||||||
# logs
|
# logs
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ function _M.access(conf, ctx)
|
|||||||
core.log.info("REQUEST_DEBUG: uri = "..request_uri)
|
core.log.info("REQUEST_DEBUG: uri = "..request_uri)
|
||||||
|
|
||||||
local white_list = {
|
local white_list = {
|
||||||
|
["/api/v3/sms/send"] = true,
|
||||||
["/api/v3/login"] = true,
|
["/api/v3/login"] = true,
|
||||||
|
["/api/v3/version"] = true,
|
||||||
|
|
||||||
["/admin/v3/login"] = true,
|
["/admin/v3/login"] = true,
|
||||||
["/admin/v3/refresh"] = true,
|
["/admin/v3/refresh"] = true,
|
||||||
["/api/v3/version"] = true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local user_key = core.request.header(ctx, "authorization")
|
local user_key = core.request.header(ctx, "authorization")
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ go 1.26
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
buf.build/go/protovalidate v0.14.0
|
buf.build/go/protovalidate v0.14.0
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi v0.2.1
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18
|
||||||
github.com/alibabacloud-go/sts-20150401/v2 v2.1.0
|
github.com/alibabacloud-go/sts-20150401/v2 v2.1.0
|
||||||
github.com/alibabacloud-go/tea v1.5.3
|
github.com/alibabacloud-go/tea v1.5.3
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.9
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9
|
||||||
@@ -15,6 +17,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/mssola/user_agent v0.6.0
|
github.com/mssola/user_agent v0.6.0
|
||||||
github.com/redis/go-redis/v9 v9.21.0
|
github.com/redis/go-redis/v9 v9.21.0
|
||||||
|
github.com/samber/lo v1.53.0
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/xuri/excelize/v2 v2.11.0
|
github.com/xuri/excelize/v2 v2.11.0
|
||||||
github.com/zeromicro/go-zero v1.10.3
|
github.com/zeromicro/go-zero v1.10.3
|
||||||
@@ -35,7 +38,10 @@ require (
|
|||||||
filippo.io/edwards25519 v1.2.0 // indirect
|
filippo.io/edwards25519 v1.2.0 // indirect
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.8 // indirect
|
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect
|
||||||
github.com/aliyun/credentials-go v1.4.13 // indirect
|
github.com/aliyun/credentials-go v1.4.13 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
@@ -109,7 +115,6 @@ require (
|
|||||||
github.com/richardlehane/mscfb v1.0.7 // indirect
|
github.com/richardlehane/mscfb v1.0.7 // indirect
|
||||||
github.com/richardlehane/msoleps v1.0.6 // indirect
|
github.com/richardlehane/msoleps v1.0.6 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||||
github.com/samber/lo v1.53.0 // indirect
|
|
||||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
github.com/spf13/afero v1.15.0 // indirect
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
|
|||||||
@@ -19,21 +19,26 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC
|
|||||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||||
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||||
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4 h1:o6veen0IZ/Fe1JawwhwQMZcbw67CVDY1pQwXcNWPyQo=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4 h1:o6veen0IZ/Fe1JawwhwQMZcbw67CVDY1pQwXcNWPyQo=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4/go.mod h1:eHjVxrT9g8uVYN/nyAwOFQEfkVA154ChiqRc2XnNKYU=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.4/go.mod h1:eHjVxrT9g8uVYN/nyAwOFQEfkVA154ChiqRc2XnNKYU=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||||
|
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||||
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||||
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
||||||
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.8 h1:aDPyz6C+nenypx24N5qEt09NjpS6mu7Cu1A+wf9UTaY=
|
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 h1:hfZA4cgIl6frNdsRmAyj8sn9J1bihQpYbzIVv2T/+Cs=
|
||||||
github.com/alibabacloud-go/dysmsapi-20180501/v2 v2.0.8/go.mod h1:e/vWJ5gLVnraPROSh+3oMSodf5ukaUlqNgH0IIcnz98=
|
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18/go.mod h1:di54xjBFHvKiQQo7st3TUmiMy0ywne5TOHup786Rhes=
|
||||||
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||||
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
|
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
|
||||||
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||||
github.com/alibabacloud-go/sts-20150401/v2 v2.1.0 h1:Z5FOpAW003CjNSEPSemkPGj+OHWvF5bu7gz+Rdx/1zU=
|
github.com/alibabacloud-go/sts-20150401/v2 v2.1.0 h1:Z5FOpAW003CjNSEPSemkPGj+OHWvF5bu7gz+Rdx/1zU=
|
||||||
@@ -43,18 +48,23 @@ github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeG
|
|||||||
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||||
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
github.com/alibabacloud-go/tea v1.5.2/go.mod h1:hgSs82CkOiehSQMoiFN79dL6zsGX7pVGvnn9SIEs8/0=
|
github.com/alibabacloud-go/tea v1.5.2/go.mod h1:hgSs82CkOiehSQMoiFN79dL6zsGX7pVGvnn9SIEs8/0=
|
||||||
github.com/alibabacloud-go/tea v1.5.3 h1:UMJTBcO48w7Zz1nlFe9bmRsHwgB7AjF8DBQzcvHhIp8=
|
github.com/alibabacloud-go/tea v1.5.3 h1:UMJTBcO48w7Zz1nlFe9bmRsHwgB7AjF8DBQzcvHhIp8=
|
||||||
github.com/alibabacloud-go/tea v1.5.3/go.mod h1:hgSs82CkOiehSQMoiFN79dL6zsGX7pVGvnn9SIEs8/0=
|
github.com/alibabacloud-go/tea v1.5.3/go.mod h1:hgSs82CkOiehSQMoiFN79dL6zsGX7pVGvnn9SIEs8/0=
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
|
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.9 h1:y6pUIlhjxbZl9ObDAcmA1H3c21eaAxADHTDQmBnAIgA=
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9 h1:y6pUIlhjxbZl9ObDAcmA1H3c21eaAxADHTDQmBnAIgA=
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.9/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M=
|
||||||
|
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||||
github.com/alicebob/miniredis/v2 v2.38.0 h1:nZAzCR+Lj+Vxk4ZXzm2NuKq2O33RXj1XxJ2e2uP9jiw=
|
github.com/alicebob/miniredis/v2 v2.38.0 h1:nZAzCR+Lj+Vxk4ZXzm2NuKq2O33RXj1XxJ2e2uP9jiw=
|
||||||
github.com/alicebob/miniredis/v2 v2.38.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
github.com/alicebob/miniredis/v2 v2.38.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
||||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||||
@@ -86,6 +96,8 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9
|
|||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
|
github.com/clbanning/mxj/v2 v2.5.6/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package aliyun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
openapi "github.com/alibabacloud-go/darabonba-openapi/client"
|
||||||
|
dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v2/client"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
cli *dysmsapi.Client
|
||||||
|
signName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(accessKeyId, accessKeySecret, signName, endpoint string) (*Client, error) {
|
||||||
|
config := &openapi.Config{
|
||||||
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
Endpoint: tea.String(endpoint),
|
||||||
|
}
|
||||||
|
cli, err := dysmsapi.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Client{cli: cli, signName: signName}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Send(phone, templateCode string, params map[string]string) error {
|
||||||
|
if phone == "" || templateCode == "" {
|
||||||
|
return fmt.Errorf("phone and templateCode are required")
|
||||||
|
}
|
||||||
|
|
||||||
|
var templateParam *string
|
||||||
|
if len(params) > 0 {
|
||||||
|
raw, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshal template params: %w", err)
|
||||||
|
}
|
||||||
|
templateParam = tea.String(string(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.cli.SendSms(&dysmsapi.SendSmsRequest{
|
||||||
|
PhoneNumbers: tea.String(phone),
|
||||||
|
SignName: tea.String(c.signName),
|
||||||
|
TemplateCode: tea.String(templateCode),
|
||||||
|
TemplateParam: templateParam,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp == nil || resp.Body == nil {
|
||||||
|
return fmt.Errorf("aliyun sms: empty response")
|
||||||
|
}
|
||||||
|
if code := tea.StringValue(resp.Body.Code); code != "OK" {
|
||||||
|
return fmt.Errorf("aliyun sms: %s %s", code, tea.StringValue(resp.Body.Message))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package sms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"lone-services/pkg/sms/aliyun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TemplateKind string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TemplateCode TemplateKind = "code"
|
||||||
|
TemplatePassword TemplateKind = "password"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SMS interface {
|
||||||
|
Send(phone string, templateCode string, params map[string]string) error
|
||||||
|
SendByKind(phone string, kind TemplateKind, params map[string]string) error
|
||||||
|
Template(kind TemplateKind) string
|
||||||
|
Timeout() int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
AccessKeyId string
|
||||||
|
AccessKeySecret string
|
||||||
|
SignName string
|
||||||
|
Endpoint string
|
||||||
|
TemplateCode string
|
||||||
|
TemplatePwd string
|
||||||
|
Timeout int
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
sender *aliyun.Client
|
||||||
|
templates map[TemplateKind]string
|
||||||
|
timeout int
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config) (SMS, error) {
|
||||||
|
if cfg.AccessKeyId == "" || cfg.AccessKeySecret == "" || cfg.SignName == "" {
|
||||||
|
return nil, fmt.Errorf("config missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
sender, err := aliyun.New(cfg.AccessKeyId, cfg.AccessKeySecret, cfg.SignName, cfg.Endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cfg.Timeout <= 0 {
|
||||||
|
cfg.Timeout = 600
|
||||||
|
}
|
||||||
|
return &client{
|
||||||
|
sender: sender,
|
||||||
|
templates: map[TemplateKind]string{
|
||||||
|
TemplateCode: cfg.TemplateCode,
|
||||||
|
TemplatePassword: cfg.TemplatePwd,
|
||||||
|
},
|
||||||
|
timeout: cfg.Timeout,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) Send(phone, templateCode string, params map[string]string) error {
|
||||||
|
return c.sender.Send(phone, templateCode, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) SendByKind(phone string, kind TemplateKind, params map[string]string) error {
|
||||||
|
code := c.Template(kind)
|
||||||
|
if code == "" {
|
||||||
|
return fmt.Errorf("sms template not configured for kind %s", kind)
|
||||||
|
}
|
||||||
|
return c.Send(phone, code, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) Template(kind TemplateKind) string { return c.templates[kind] }
|
||||||
|
func (c *client) Timeout() int { return c.timeout }
|
||||||
+93
-36
@@ -82,15 +82,14 @@ func (x *Response) GetData() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统一登录:grant_type = openid | password | sms
|
|
||||||
type LoginReq struct {
|
type LoginReq struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
ClientCode string `protobuf:"bytes,1,opt,name=client_code,json=clientCode,proto3" json:"client_code,omitempty"` // 端编码,如 user_skin / user_o2 / sale_beauty
|
ClientCode string `protobuf:"bytes,1,opt,name=client_code,json=clientCode,proto3" json:"client_code,omitempty"`
|
||||||
GrantType string `protobuf:"bytes,2,opt,name=grant_type,json=grantType,proto3" json:"grant_type,omitempty"` // openid | password | sms
|
GrantType string `protobuf:"bytes,2,opt,name=grant_type,json=grantType,proto3" json:"grant_type,omitempty"`
|
||||||
Code string `protobuf:"bytes,3,opt,name=code,proto3" json:"code,omitempty"` // grant_type=openid 时传微信 login code
|
Code string `protobuf:"bytes,3,opt,name=code,proto3" json:"code,omitempty"`
|
||||||
Mobile string `protobuf:"bytes,4,opt,name=mobile,proto3" json:"mobile,omitempty"` // grant_type=password|sms
|
Mobile string `protobuf:"bytes,4,opt,name=mobile,proto3" json:"mobile,omitempty"`
|
||||||
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` // grant_type=password
|
Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"`
|
||||||
SmsCode string `protobuf:"bytes,6,opt,name=sms_code,json=smsCode,proto3" json:"sms_code,omitempty"` // grant_type=sms
|
SmsCode string `protobuf:"bytes,6,opt,name=sms_code,json=smsCode,proto3" json:"sms_code,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -167,7 +166,6 @@ func (x *LoginReq) GetSmsCode() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理端用户列表
|
|
||||||
type UserItemsReq struct {
|
type UserItemsReq struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Mobile string `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"`
|
Mobile string `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"`
|
||||||
@@ -228,7 +226,6 @@ func (x *UserItemsReq) GetSize() int32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理端修改用户状态
|
|
||||||
type UserStatusReq struct {
|
type UserStatusReq struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
@@ -837,6 +834,58 @@ func (x *RevokeBizClientData) GetRevoked() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SendSmsReq struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Mobile string `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"`
|
||||||
|
Scene int32 `protobuf:"varint,2,opt,name=scene,proto3" json:"scene,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SendSmsReq) Reset() {
|
||||||
|
*x = SendSmsReq{}
|
||||||
|
mi := &file_user_user_proto_msgTypes[13]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SendSmsReq) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SendSmsReq) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SendSmsReq) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_user_user_proto_msgTypes[13]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SendSmsReq.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SendSmsReq) Descriptor() ([]byte, []int) {
|
||||||
|
return file_user_user_proto_rawDescGZIP(), []int{13}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SendSmsReq) GetMobile() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Mobile
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SendSmsReq) GetScene() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Scene
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type InfoReq struct {
|
type InfoReq struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@@ -845,7 +894,7 @@ type InfoReq struct {
|
|||||||
|
|
||||||
func (x *InfoReq) Reset() {
|
func (x *InfoReq) Reset() {
|
||||||
*x = InfoReq{}
|
*x = InfoReq{}
|
||||||
mi := &file_user_user_proto_msgTypes[13]
|
mi := &file_user_user_proto_msgTypes[14]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -857,7 +906,7 @@ func (x *InfoReq) String() string {
|
|||||||
func (*InfoReq) ProtoMessage() {}
|
func (*InfoReq) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *InfoReq) ProtoReflect() protoreflect.Message {
|
func (x *InfoReq) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_user_user_proto_msgTypes[13]
|
mi := &file_user_user_proto_msgTypes[14]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -870,7 +919,7 @@ func (x *InfoReq) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use InfoReq.ProtoReflect.Descriptor instead.
|
// Deprecated: Use InfoReq.ProtoReflect.Descriptor instead.
|
||||||
func (*InfoReq) Descriptor() ([]byte, []int) {
|
func (*InfoReq) Descriptor() ([]byte, []int) {
|
||||||
return file_user_user_proto_rawDescGZIP(), []int{13}
|
return file_user_user_proto_rawDescGZIP(), []int{14}
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_user_user_proto protoreflect.FileDescriptor
|
var File_user_user_proto protoreflect.FileDescriptor
|
||||||
@@ -939,9 +988,14 @@ const file_user_user_proto_rawDesc = "" +
|
|||||||
"\vclient_code\x18\x02 \x01(\tR\n" +
|
"\vclient_code\x18\x02 \x01(\tR\n" +
|
||||||
"clientCode\"/\n" +
|
"clientCode\"/\n" +
|
||||||
"\x13RevokeBizClientData\x12\x18\n" +
|
"\x13RevokeBizClientData\x12\x18\n" +
|
||||||
"\arevoked\x18\x01 \x01(\bR\arevoked\"\t\n" +
|
"\arevoked\x18\x01 \x01(\bR\arevoked\":\n" +
|
||||||
"\aInfoReq2\xc3\x04\n" +
|
"\n" +
|
||||||
"\x04User\x12A\n" +
|
"SendSmsReq\x12\x16\n" +
|
||||||
|
"\x06mobile\x18\x01 \x01(\tR\x06mobile\x12\x14\n" +
|
||||||
|
"\x05scene\x18\x02 \x01(\x05R\x05scene\"\t\n" +
|
||||||
|
"\aInfoReq2\x8d\x05\n" +
|
||||||
|
"\x04User\x12H\n" +
|
||||||
|
"\aSendSms\x12\x10.user.SendSmsReq\x1a\x0e.user.Response\"\x1b\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/api/v3/sms/send\x12A\n" +
|
||||||
"\x05Login\x12\x0e.user.LoginReq\x1a\x0e.user.Response\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/api/v3/login\x12C\n" +
|
"\x05Login\x12\x0e.user.LoginReq\x1a\x0e.user.Response\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/api/v3/login\x12C\n" +
|
||||||
"\x04Info\x12\r.user.InfoReq\x1a\x0e.user.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/api/v3/user/info\x12P\n" +
|
"\x04Info\x12\r.user.InfoReq\x1a\x0e.user.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/api/v3/user/info\x12P\n" +
|
||||||
"\tUserItems\x12\x12.user.UserItemsReq\x1a\x0e.user.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\x12\x14/admin/v3/user/items\x12S\n" +
|
"\tUserItems\x12\x12.user.UserItemsReq\x1a\x0e.user.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\x12\x14/admin/v3/user/items\x12S\n" +
|
||||||
@@ -965,7 +1019,7 @@ func file_user_user_proto_rawDescGZIP() []byte {
|
|||||||
return file_user_user_proto_rawDescData
|
return file_user_user_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
|
var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
|
||||||
var file_user_user_proto_goTypes = []any{
|
var file_user_user_proto_goTypes = []any{
|
||||||
(*Response)(nil), // 0: user.Response
|
(*Response)(nil), // 0: user.Response
|
||||||
(*LoginReq)(nil), // 1: user.LoginReq
|
(*LoginReq)(nil), // 1: user.LoginReq
|
||||||
@@ -980,28 +1034,31 @@ var file_user_user_proto_goTypes = []any{
|
|||||||
(*UpdateMobileData)(nil), // 10: user.UpdateMobileData
|
(*UpdateMobileData)(nil), // 10: user.UpdateMobileData
|
||||||
(*RevokeBizClientReq)(nil), // 11: user.RevokeBizClientReq
|
(*RevokeBizClientReq)(nil), // 11: user.RevokeBizClientReq
|
||||||
(*RevokeBizClientData)(nil), // 12: user.RevokeBizClientData
|
(*RevokeBizClientData)(nil), // 12: user.RevokeBizClientData
|
||||||
(*InfoReq)(nil), // 13: user.InfoReq
|
(*SendSmsReq)(nil), // 13: user.SendSmsReq
|
||||||
|
(*InfoReq)(nil), // 14: user.InfoReq
|
||||||
}
|
}
|
||||||
var file_user_user_proto_depIdxs = []int32{
|
var file_user_user_proto_depIdxs = []int32{
|
||||||
7, // 0: user.UsersByIdsData.items:type_name -> user.UserBriefItem
|
7, // 0: user.UsersByIdsData.items:type_name -> user.UserBriefItem
|
||||||
1, // 1: user.User.Login:input_type -> user.LoginReq
|
13, // 1: user.User.SendSms:input_type -> user.SendSmsReq
|
||||||
13, // 2: user.User.Info:input_type -> user.InfoReq
|
1, // 2: user.User.Login:input_type -> user.LoginReq
|
||||||
2, // 3: user.User.UserItems:input_type -> user.UserItemsReq
|
14, // 3: user.User.Info:input_type -> user.InfoReq
|
||||||
3, // 4: user.User.UserStatus:input_type -> user.UserStatusReq
|
2, // 4: user.User.UserItems:input_type -> user.UserItemsReq
|
||||||
4, // 5: user.User.EnsureBizIdentity:input_type -> user.EnsureBizIdentityReq
|
3, // 5: user.User.UserStatus:input_type -> user.UserStatusReq
|
||||||
6, // 6: user.User.UsersByIds:input_type -> user.UsersByIdsReq
|
4, // 6: user.User.EnsureBizIdentity:input_type -> user.EnsureBizIdentityReq
|
||||||
9, // 7: user.User.UpdateMobile:input_type -> user.UpdateMobileReq
|
6, // 7: user.User.UsersByIds:input_type -> user.UsersByIdsReq
|
||||||
11, // 8: user.User.RevokeBizClient:input_type -> user.RevokeBizClientReq
|
9, // 8: user.User.UpdateMobile:input_type -> user.UpdateMobileReq
|
||||||
0, // 9: user.User.Login:output_type -> user.Response
|
11, // 9: user.User.RevokeBizClient:input_type -> user.RevokeBizClientReq
|
||||||
0, // 10: user.User.Info:output_type -> user.Response
|
0, // 10: user.User.SendSms:output_type -> user.Response
|
||||||
0, // 11: user.User.UserItems:output_type -> user.Response
|
0, // 11: user.User.Login:output_type -> user.Response
|
||||||
0, // 12: user.User.UserStatus:output_type -> user.Response
|
0, // 12: user.User.Info:output_type -> user.Response
|
||||||
5, // 13: user.User.EnsureBizIdentity:output_type -> user.EnsureBizIdentityData
|
0, // 13: user.User.UserItems:output_type -> user.Response
|
||||||
8, // 14: user.User.UsersByIds:output_type -> user.UsersByIdsData
|
0, // 14: user.User.UserStatus:output_type -> user.Response
|
||||||
10, // 15: user.User.UpdateMobile:output_type -> user.UpdateMobileData
|
5, // 15: user.User.EnsureBizIdentity:output_type -> user.EnsureBizIdentityData
|
||||||
12, // 16: user.User.RevokeBizClient:output_type -> user.RevokeBizClientData
|
8, // 16: user.User.UsersByIds:output_type -> user.UsersByIdsData
|
||||||
9, // [9:17] is the sub-list for method output_type
|
10, // 17: user.User.UpdateMobile:output_type -> user.UpdateMobileData
|
||||||
1, // [1:9] is the sub-list for method input_type
|
12, // 18: user.User.RevokeBizClient:output_type -> user.RevokeBizClientData
|
||||||
|
10, // [10:19] is the sub-list for method output_type
|
||||||
|
1, // [1:10] is the sub-list for method input_type
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
0, // [0:1] is the sub-list for field type_name
|
0, // [0:1] is the sub-list for field type_name
|
||||||
@@ -1018,7 +1075,7 @@ func file_user_user_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_user_proto_rawDesc), len(file_user_user_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_user_proto_rawDesc), len(file_user_user_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 14,
|
NumMessages: 15,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
const _ = grpc.SupportPackageIsVersion9
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
User_SendSms_FullMethodName = "/user.User/SendSms"
|
||||||
User_Login_FullMethodName = "/user.User/Login"
|
User_Login_FullMethodName = "/user.User/Login"
|
||||||
User_Info_FullMethodName = "/user.User/Info"
|
User_Info_FullMethodName = "/user.User/Info"
|
||||||
User_UserItems_FullMethodName = "/user.User/UserItems"
|
User_UserItems_FullMethodName = "/user.User/UserItems"
|
||||||
@@ -33,6 +34,7 @@ const (
|
|||||||
//
|
//
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
type UserClient interface {
|
type UserClient interface {
|
||||||
|
SendSms(ctx context.Context, in *SendSmsReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
|
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
|
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
|
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
@@ -51,6 +53,16 @@ func NewUserClient(cc grpc.ClientConnInterface) UserClient {
|
|||||||
return &userClient{cc}
|
return &userClient{cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *userClient) SendSms(ctx context.Context, in *SendSmsReq, opts ...grpc.CallOption) (*Response, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(Response)
|
||||||
|
err := c.cc.Invoke(ctx, User_SendSms_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) {
|
func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
out := new(Response)
|
out := new(Response)
|
||||||
@@ -135,6 +147,7 @@ func (c *userClient) RevokeBizClient(ctx context.Context, in *RevokeBizClientReq
|
|||||||
// All implementations must embed UnimplementedUserServer
|
// All implementations must embed UnimplementedUserServer
|
||||||
// for forward compatibility.
|
// for forward compatibility.
|
||||||
type UserServer interface {
|
type UserServer interface {
|
||||||
|
SendSms(context.Context, *SendSmsReq) (*Response, error)
|
||||||
Login(context.Context, *LoginReq) (*Response, error)
|
Login(context.Context, *LoginReq) (*Response, error)
|
||||||
Info(context.Context, *InfoReq) (*Response, error)
|
Info(context.Context, *InfoReq) (*Response, error)
|
||||||
UserItems(context.Context, *UserItemsReq) (*Response, error)
|
UserItems(context.Context, *UserItemsReq) (*Response, error)
|
||||||
@@ -153,6 +166,9 @@ type UserServer interface {
|
|||||||
// pointer dereference when methods are called.
|
// pointer dereference when methods are called.
|
||||||
type UnimplementedUserServer struct{}
|
type UnimplementedUserServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedUserServer) SendSms(context.Context, *SendSmsReq) (*Response, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method SendSms not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*Response, error) {
|
func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*Response, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method Login not implemented")
|
return nil, status.Error(codes.Unimplemented, "method Login not implemented")
|
||||||
}
|
}
|
||||||
@@ -198,6 +214,24 @@ func RegisterUserServer(s grpc.ServiceRegistrar, srv UserServer) {
|
|||||||
s.RegisterService(&User_ServiceDesc, srv)
|
s.RegisterService(&User_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _User_SendSms_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SendSmsReq)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(UserServer).SendSms(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: User_SendSms_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(UserServer).SendSms(ctx, req.(*SendSmsReq))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(LoginReq)
|
in := new(LoginReq)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -349,6 +383,10 @@ var User_ServiceDesc = grpc.ServiceDesc{
|
|||||||
ServiceName: "user.User",
|
ServiceName: "user.User",
|
||||||
HandlerType: (*UserServer)(nil),
|
HandlerType: (*UserServer)(nil),
|
||||||
Methods: []grpc.MethodDesc{
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "SendSms",
|
||||||
|
Handler: _User_SendSms_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "Login",
|
MethodName: "Login",
|
||||||
Handler: _User_Login_Handler,
|
Handler: _User_Login_Handler,
|
||||||
|
|||||||
Binary file not shown.
@@ -87,9 +87,20 @@ message RevokeBizClientData {
|
|||||||
bool revoked = 1;
|
bool revoked = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SendSmsReq {
|
||||||
|
string mobile = 1;
|
||||||
|
int32 scene = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message InfoReq {}
|
message InfoReq {}
|
||||||
|
|
||||||
service User {
|
service User {
|
||||||
|
rpc SendSms(SendSmsReq) returns (Response) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/api/v3/sms/send"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
}
|
||||||
rpc Login(LoginReq) returns (Response) {
|
rpc Login(LoginReq) returns (Response) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/api/v3/login"
|
post: "/api/v3/login"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"lone-services/pkg/sms"
|
||||||
|
"lone-services/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewSMS() (sms.SMS, error) {
|
||||||
|
|
||||||
|
return sms.New(sms.Config{
|
||||||
|
AccessKeyId: utils.GetConfigString("sms.accessKeyId"),
|
||||||
|
AccessKeySecret: utils.GetConfigString("sms.accessKeySecret"),
|
||||||
|
SignName: utils.GetConfigString("sms.signName"),
|
||||||
|
Endpoint: utils.GetConfigString("sms.endpoint"),
|
||||||
|
TemplateCode: utils.GetConfigString("sms.template.code"),
|
||||||
|
TemplatePwd: utils.GetConfigString("sms.template.password"),
|
||||||
|
Timeout: utils.GetConfigInt("sms.timeout"),
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -13,15 +13,19 @@ const (
|
|||||||
GrantTypePassword = "password"
|
GrantTypePassword = "password"
|
||||||
GrantTypeSms = "sms"
|
GrantTypeSms = "sms"
|
||||||
|
|
||||||
// Type* 登录身份(写入 session.type / X-User-Type),与订单侧约定一致
|
SmsSceneLogin int32 = 1
|
||||||
TypeSale uint8 = 1 // 销售
|
SmsSceneResetPassword int32 = 2
|
||||||
TypeStore uint8 = 2 // 门店
|
|
||||||
TypeUser uint8 = 3 // 普通用户
|
SmsRateLimitSeconds = 60
|
||||||
|
SmsCodeLength = 6
|
||||||
|
|
||||||
|
TypeSale uint8 = 1
|
||||||
|
TypeStore uint8 = 2
|
||||||
|
TypeUser uint8 = 3
|
||||||
|
|
||||||
SubjectTypeSale = "sale"
|
SubjectTypeSale = "sale"
|
||||||
SubjectTypeStore = "store"
|
SubjectTypeStore = "store"
|
||||||
SubjectTypeUser = "user"
|
SubjectTypeUser = "user"
|
||||||
|
|
||||||
// ExtraJsonEmpty MySQL JSON 列不能写空串,无扩展字段时用 {}
|
|
||||||
ExtraJsonEmpty = "{}"
|
ExtraJsonEmpty = "{}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"lone-services/pkg/redis"
|
||||||
|
"lone-services/pkg/sms"
|
||||||
|
"lone-services/pkg/utils"
|
||||||
|
"lone-services/pkg/validate"
|
||||||
|
user "lone-services/rpc/user/pb"
|
||||||
|
"lone-services/services/user/internal/dao"
|
||||||
|
"lone-services/services/user/internal/svc"
|
||||||
|
"lone-services/services/user/validator"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SendSmsLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLogic {
|
||||||
|
return &SendSmsLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *SendSmsLogic) SendSms(in *user.SendSmsReq) (*user.Response, error) {
|
||||||
|
var req validator.SendSmsValidator
|
||||||
|
if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty {
|
||||||
|
return outResponse(utils.ErrorParams, msg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.svcCtx.SMS == nil {
|
||||||
|
return outResponse(utils.Fail, "短信服务未配置"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
kind, ok := smsSceneKind(req.Scene)
|
||||||
|
if !ok {
|
||||||
|
return outResponse(utils.ErrorParams, "短信场景不正确"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
freqKey := smsFreqRedisKey(req.Scene, req.Mobile)
|
||||||
|
okSet, err := redis.Client.SetNX(l.ctx, freqKey, "1", time.Duration(dao.SmsRateLimitSeconds)*time.Second).Result()
|
||||||
|
if err != nil {
|
||||||
|
l.Errorf("sms freq setnx: %v", err)
|
||||||
|
return failResponse(utils.Fail), nil
|
||||||
|
}
|
||||||
|
if !okSet {
|
||||||
|
return outResponse(utils.ErrorParams, "发送过于频繁,请稍后再试"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
code, err := genDigitCode(dao.SmsCodeLength)
|
||||||
|
if err != nil {
|
||||||
|
_ = redis.Client.Del(l.ctx, freqKey).Err()
|
||||||
|
l.Errorf("sms gen code: %v", err)
|
||||||
|
return failResponse(utils.Fail), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := l.svcCtx.SMS.SendByKind(req.Mobile, kind, map[string]string{"code": code}); err != nil {
|
||||||
|
_ = redis.Client.Del(l.ctx, freqKey).Err()
|
||||||
|
l.Errorf("sms send: %v", err)
|
||||||
|
return outResponse(utils.Fail, "短信发送失败"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ttl := l.svcCtx.SMS.Timeout()
|
||||||
|
if ttl <= utils.NumberZero {
|
||||||
|
ttl = 600
|
||||||
|
}
|
||||||
|
codeKey := smsCodeRedisKey(req.Scene, req.Mobile)
|
||||||
|
if err := redis.Client.Set(l.ctx, codeKey, code, time.Duration(ttl)*time.Second).Err(); err != nil {
|
||||||
|
l.Errorf("sms cache code: %v", err)
|
||||||
|
return failResponse(utils.Fail), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return okResponse(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func smsSceneKind(scene int32) (sms.TemplateKind, bool) {
|
||||||
|
switch scene {
|
||||||
|
case dao.SmsSceneLogin:
|
||||||
|
return sms.TemplateCode, true
|
||||||
|
case dao.SmsSceneResetPassword:
|
||||||
|
return sms.TemplatePassword, true
|
||||||
|
default:
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func smsCodeRedisKey(scene int32, mobile string) string {
|
||||||
|
return utils.CodeKey + strconv.Itoa(int(scene)) + ":" + mobile
|
||||||
|
}
|
||||||
|
|
||||||
|
func smsFreqRedisKey(scene int32, mobile string) string {
|
||||||
|
return "sms:freq:" + strconv.Itoa(int(scene)) + ":" + mobile
|
||||||
|
}
|
||||||
|
|
||||||
|
func genDigitCode(length int) (string, error) {
|
||||||
|
if length <= utils.NumberZero {
|
||||||
|
return utils.StringEmpty, fmt.Errorf("invalid code length")
|
||||||
|
}
|
||||||
|
out := make([]byte, length)
|
||||||
|
for i := range out {
|
||||||
|
n, err := rand.Int(rand.Reader, big.NewInt(10))
|
||||||
|
if err != nil {
|
||||||
|
return utils.StringEmpty, err
|
||||||
|
}
|
||||||
|
out[i] = byte('0' + n.Int64())
|
||||||
|
}
|
||||||
|
return string(out), nil
|
||||||
|
}
|
||||||
@@ -23,6 +23,11 @@ func NewUserServer(svcCtx *svc.ServiceContext) *UserServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *UserServer) SendSms(ctx context.Context, in *user.SendSmsReq) (*user.Response, error) {
|
||||||
|
l := logic.NewSendSmsLogic(ctx, s.svcCtx)
|
||||||
|
return l.SendSms(in)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UserServer) Login(ctx context.Context, in *user.LoginReq) (*user.Response, error) {
|
func (s *UserServer) Login(ctx context.Context, in *user.LoginReq) (*user.Response, error) {
|
||||||
l := logic.NewLoginLogic(ctx, s.svcCtx)
|
l := logic.NewLoginLogic(ctx, s.svcCtx)
|
||||||
return l.Login(in)
|
return l.Login(in)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package svc
|
package svc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"lone-services/pkg/sms"
|
||||||
"lone-services/pkg/utils"
|
"lone-services/pkg/utils"
|
||||||
"lone-services/services/user/internal/config"
|
"lone-services/services/user/internal/config"
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ type ServiceContext struct {
|
|||||||
Prefix string
|
Prefix string
|
||||||
JWT *config.JWTAuth
|
JWT *config.JWTAuth
|
||||||
SaleSvcName string
|
SaleSvcName string
|
||||||
|
SMS sms.SMS
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config, db *gorm.DB, jwtAuth *config.JWTAuth) *ServiceContext {
|
func NewServiceContext(c config.Config, db *gorm.DB, jwtAuth *config.JWTAuth) *ServiceContext {
|
||||||
@@ -21,11 +23,18 @@ func NewServiceContext(c config.Config, db *gorm.DB, jwtAuth *config.JWTAuth) *S
|
|||||||
if saleSvc == utils.StringEmpty {
|
if saleSvc == utils.StringEmpty {
|
||||||
logx.Error("config services.sale empty")
|
logx.Error("config services.sale empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
smsClient, err := config.NewSMS()
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("sms init: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
DB: db,
|
DB: db,
|
||||||
Prefix: utils.GetConfigString("mysql.prefix"),
|
Prefix: utils.GetConfigString("mysql.prefix"),
|
||||||
JWT: jwtAuth,
|
JWT: jwtAuth,
|
||||||
SaleSvcName: saleSvc,
|
SaleSvcName: saleSvc,
|
||||||
|
SMS: smsClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ type (
|
|||||||
Response = user.Response
|
Response = user.Response
|
||||||
RevokeBizClientData = user.RevokeBizClientData
|
RevokeBizClientData = user.RevokeBizClientData
|
||||||
RevokeBizClientReq = user.RevokeBizClientReq
|
RevokeBizClientReq = user.RevokeBizClientReq
|
||||||
|
SendSmsReq = user.SendSmsReq
|
||||||
UpdateMobileData = user.UpdateMobileData
|
UpdateMobileData = user.UpdateMobileData
|
||||||
UpdateMobileReq = user.UpdateMobileReq
|
UpdateMobileReq = user.UpdateMobileReq
|
||||||
UserBriefItem = user.UserBriefItem
|
UserBriefItem = user.UserBriefItem
|
||||||
@@ -30,6 +31,7 @@ type (
|
|||||||
UsersByIdsReq = user.UsersByIdsReq
|
UsersByIdsReq = user.UsersByIdsReq
|
||||||
|
|
||||||
User interface {
|
User interface {
|
||||||
|
SendSms(ctx context.Context, in *SendSmsReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
|
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
|
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
|
UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error)
|
||||||
@@ -51,6 +53,11 @@ func NewUser(cli zrpc.Client) User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *defaultUser) SendSms(ctx context.Context, in *SendSmsReq, opts ...grpc.CallOption) (*Response, error) {
|
||||||
|
client := user.NewUserClient(m.cli.Conn())
|
||||||
|
return client.SendSms(ctx, in, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *defaultUser) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) {
|
func (m *defaultUser) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) {
|
||||||
client := user.NewUserClient(m.cli.Conn())
|
client := user.NewUserClient(m.cli.Conn())
|
||||||
return client.Login(ctx, in, opts...)
|
return client.Login(ctx, in, opts...)
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ type LoginValidator struct {
|
|||||||
SmsCode string `validate:"required_if=GrantType sms,omitempty,max=8"`
|
SmsCode string `validate:"required_if=GrantType sms,omitempty,max=8"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SendSmsValidator struct {
|
||||||
|
Mobile string `validate:"required,len=11"`
|
||||||
|
Scene int32 `validate:"required,oneof=1 2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p SendSmsValidator) GetMessage() validate.ValidatorMessages {
|
||||||
|
return validate.ValidatorMessages{
|
||||||
|
"Mobile.required": "手机号不能为空",
|
||||||
|
"Mobile.len": "手机号格式错误",
|
||||||
|
"Scene.required": "短信场景不能为空",
|
||||||
|
"Scene.oneof": "短信场景不正确",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p LoginValidator) GetMessage() validate.ValidatorMessages {
|
func (p LoginValidator) GetMessage() validate.ValidatorMessages {
|
||||||
return validate.ValidatorMessages{
|
return validate.ValidatorMessages{
|
||||||
"ClientCode.required": "端编码不能为空",
|
"ClientCode.required": "端编码不能为空",
|
||||||
|
|||||||
Reference in New Issue
Block a user