Commit d2b118c1 authored by 黄智's avatar 黄智

忘记密码

parent cb700e91
......@@ -5,6 +5,7 @@ go 1.19
require (
github.com/360EntSecGroup-Skylar/excelize v1.4.1
github.com/Luzifer/go-openssl/v4 v4.1.0
github.com/aliyun/alibaba-cloud-sdk-go v1.62.431
github.com/bytedance/go-tagexpr v2.7.4+incompatible
github.com/ghodss/yaml v1.0.0
github.com/gin-gonic/gin v1.9.0
......@@ -46,6 +47,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/henrylee2cn/ameda v1.5.0 // indirect
github.com/henrylee2cn/goutil v0.0.0-20220704075712-42f2ec55fe8d // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.3 // indirect
......@@ -57,6 +59,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/nyaruka/phonenumbers v1.1.7 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/sirupsen/logrus v1.9.2 // indirect
......@@ -64,7 +67,7 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.9.0 // indirect
......
......@@ -18,6 +18,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.431 h1:P4qW1rrPjPDIvVc8OHNvhOXawvWD/C6opsvNYTDcXF0=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.431/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/andeya/goutil v0.0.0-20220704075712-42f2ec55fe8d h1:qZjX5KRJDCA0DaORmzyXuySdlT+MOhx0OOTbUbdPxp0=
github.com/andeya/goutil v0.0.0-20220704075712-42f2ec55fe8d/go.mod h1:jEG5/QnnhG7yGxwFUX6Q+JGMif7sjdHmmNVjn7nhJDo=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
......@@ -115,6 +117,7 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
......@@ -231,9 +234,11 @@ github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
......@@ -343,6 +348,8 @@ github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
......@@ -446,6 +453,10 @@ github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xz
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
......@@ -467,8 +478,9 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
......@@ -642,6 +654,7 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
......@@ -656,6 +669,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
......@@ -33,3 +33,18 @@ type UserOrgInfo struct {
SystemId string `json:"system_id" xorm:"system_id"` //系统账号id
IsAdmin int `json:"is_admin" xorm:"is_admin"` //用户类型
}
type SendPhoneMsg struct {
Phone string `json:"phone"`
Code string `json:"code"`
}
type ForgetPwdCheck struct {
Phone string `json:"phone" vd:"len($)>0;msg:'手机号不能为空'"` // 手机号
Code string `json:"code" vd:"len($)=6;msg:'验证码格式不正确'"` // 验证码
}
type AccountForgetPasswordReq struct {
Phone string `json:"phone" vd:"len($)>0;msg:'手机号不能为空'"` // 系统账号
Password string `json:"password" vd:"len($)>0;msg:'请输入密码'"` // 密码
}
......@@ -23,23 +23,30 @@ type SystemMenuTree struct {
PMenuId string `json:"p_menu_id" xorm:"p_menu_id"` //上级菜单id
Source string `json:"source" xorm:"source"` //源
SystemType string `json:"system_type"` //系统类型
NewWindow int `json:"new_window"` //是否开启新窗口(0 不开 1开启)
Remark string `json:"remark"` //备注说明
BuiltIn int `json:"built_in"` //是否内置 0 否 1内置数据
Child []SystemMenuTree `xorm:"-"`
}
// 系统菜单表
type SystemMenuTreePer struct {
Id int32 `json:"id" xorm:"pk autoincr" ` //id
Level int `json:"level" xorm:"level"` //菜单等级
Sort int `json:"sort" xorm:"sort"` //菜单排序
MenuName string `json:"menuName" xorm:"menu_name"` //菜单名称
DictGroupId string `json:"dict_group_id" xorm:"dict_group_id"` //字典分类id
MenuType int `json:"menuType" xorm:"menu_type"` //菜单类型(0目录1菜单2子页面)
Path string `json:"path" xorm:"menu_url"` //菜单路径
ParentPath string `json:"parentPath" xorm:"-"`
Icon string `json:"icon" xorm:"menu_logo"` //菜单图标
MenuId string `json:"menu_id" xorm:"menu_id"` //菜单id
PMenuId string `json:"p_menu_id" xorm:"p_menu_id"` //上级菜单id
SystemType string `json:"system_type"` //系统类型
Source string `json:"source" xorm:"source"` //源
Children []SystemMenuTreePer `json:"children" xorm:"-"`
Id int32 `json:"id" xorm:"pk autoincr" ` //id
Level int `json:"level" xorm:"level"` //菜单等级
Sort int `json:"sort" xorm:"sort"` //菜单排序
MenuName string `json:"menuName" xorm:"menu_name"` //菜单名称
DictGroupId string `json:"dict_group_id" xorm:"dict_group_id"` //字典分类id
MenuType int `json:"menuType" xorm:"menu_type"` //菜单类型(0目录1菜单2子页面)
Path string `json:"path" xorm:"menu_url"` //菜单路径
ParentPath string `json:"parentPath" xorm:"-"`
Icon string `json:"icon" xorm:"menu_logo"` //菜单图标
MenuId string `json:"menu_id" xorm:"menu_id"` //菜单id
PMenuId string `json:"p_menu_id" xorm:"p_menu_id"` //上级菜单id
SystemType string `json:"system_type"` //系统类型
Source string `json:"source" xorm:"source"` //源
NewWindow int `json:"new_window"` //是否开启新窗口(0 不开 1开启)
Remark string `json:"remark"` //备注说明
BuiltIn int `json:"built_in"` //是否内置 0 否 1内置数据
DisplayCondition int `json:"-"` //展示条件(0 登录 1免登录)
Children []SystemMenuTreePer `json:"children" xorm:"-"`
}
......@@ -37,14 +37,19 @@ type Config struct {
LocationKey string
PrivateKeySSH string
PublicKeySSH string
SmsAccessKeyId string
SmsAccessSecret string
SmsTemplateLogin string
SmsSignName string
}
const (
LockDuration = 1 * time.Hour //锁定时间 默认 1小时
LockErrorNumber = 3 //错误次数 3次
WIDTH = 240
HEIGHT = 60
CookieName = "bgToken"
CookieNameLastLogin string = "lastLogin"
LocalDateTimeFormat string = "2006-01-02 15:04:05"
LockDuration = 1 * time.Hour //锁定时间 默认 1小时
LockErrorNumber = 3 //错误次数 3次
WIDTH = 240
HEIGHT = 60
CookieName = "bgToken"
CookieNameLastLogin string = "lastLogin"
LocalDateTimeFormat string = "2006-01-02 15:04:05"
FinalHeartBeatUnixKey = "FinalHeartBeatUnix"
)
......@@ -6,7 +6,9 @@ import (
"github.com/gin-gonic/gin"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/constant"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/router/middleware/header"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/service"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/util"
"go.uber.org/zap"
......@@ -91,44 +93,45 @@ func UserLoginV2(c *gin.Context) {
SendJsonResponse(c, err, nil)
return
}
err = errors.New("密码错误")
SendJsonResponse(c, err, nil)
return
}
loginInf.UserUnLock(userInfo.Id)
// TODO STEP2 用户和ip没有加入到访问规则登录不上提醒
if config.AccessRuleState == 1 {
ip := util.RemoteIp(c.Request)
svc := service.AccessRuleSvc{}
if errCode := svc.CheckIp(ip, userInfo.Id); errCode != nil {
SendJsonResponse(c, errCode, nil)
return
}
}
// 密码失效提醒
subDays := util.SubDays(time.Now(), userInfo.PwdUpdatedTime)
if config.PwdValidity-subDays <= 0 && config.PwdValidity != 0 && userInfo.PwdUpdatedTime.String()[:10] != "0001-01-01" {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("密码已失效,请联系管理员修改密码!")), nil)
return
}
// 密码强弱提醒
if config.ForceUpdateState == 1 && config.MinPwdLevel > userInfo.PwdLevel {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("密码强度弱,请联系管理员修改密码!")), nil)
return
}
err = errors.New("密码错误")
SendJsonResponse(c, err, nil)
return
}
loginInf.UserUnLock(userInfo.Id)
lastLogin, msg, uuidStr, err := loginInf.LoginV2(userInfo)
if err != nil {
SendJsonResponse(c, err, "")
// TODO STEP2 用户和ip没有加入到访问规则登录不上提醒
if config.AccessRuleState == 1 {
ip := util.RemoteIp(c.Request)
svc := service.AccessRuleSvc{}
if errCode := svc.CheckIp(ip, userInfo.Id); errCode != nil {
SendJsonResponse(c, errCode, nil)
return
}
c.SetCookie(conf.CookieName, uuidStr, 1*60*60*24, "/", "", false, false)
c.SetCookie(conf.CookieNameLastLogin, lastLogin, 1*60*60*24, "/", "", false, false)
}
// 密码失效提醒
subDays := util.SubDays(time.Now(), userInfo.PwdUpdatedTime)
if config.PwdValidity-subDays <= 0 && config.PwdValidity != 0 && userInfo.PwdUpdatedTime.String()[:10] != "0001-01-01" {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("密码已失效,请联系管理员修改密码!")), nil)
return
}
// 密码强弱提醒
if config.ForceUpdateState == 1 && config.MinPwdLevel > userInfo.PwdLevel {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("密码强度弱,请联系管理员修改密码!")), nil)
return
}
SendJsonResponse(c, resp.OK, msg)
lastLogin, msg, uuidStr, err := loginInf.LoginV2(userInfo)
if err != nil {
SendJsonResponse(c, err, "")
return
}
c.SetCookie(conf.CookieName, uuidStr, 1*60*60*24, "/", "", false, false)
c.SetCookie(conf.CookieNameLastLogin, lastLogin, 1*60*60*24, "/", "", false, false)
SendJsonResponse(c, resp.OK, msg)
}
func GetUserInfo(c *gin.Context) {
token, _ := c.Cookie(conf.CookieName)
......@@ -199,3 +202,146 @@ func UserLogout(c *gin.Context) {
}
SendJsonResponse(c, resp.OK, msg)
}
// 获取短信验证码
func GetSmsVerifyCode(c *gin.Context) {
req := request.SendPhoneMsg{}
err := c.BindJSON(&req)
if err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), nil)
return
}
if !util.CheckMobile(req.Phone) {
SendJsonResponse(c, errors.New("手机号不合法!"), nil)
return
}
loginInf := service.UserSvc{}
code, err := loginInf.GetSmsVerifyCode(req.Phone)
if err != nil {
SendJsonResponse(c, err, nil)
return
}
SendJsonResponse(c, resp.OK, code)
}
func UserPhoneLogin(c *gin.Context) {
req := request.SendPhoneMsg{}
err := c.BindJSON(&req)
if err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), nil)
return
}
if !util.CheckMobile(req.Phone) {
SendJsonResponse(c, errors.New("手机号不合法!"), nil)
return
}
loginInf := service.UserSvc{}
userInfo, err := loginInf.GetUserInfo(req.Phone)
if req.Phone != userInfo.Phone {
SendJsonResponse(c, resp.DbSelectError.ErrorDetail(errors.New("手机号不正确!")), nil)
return
}
// 获取系统配置信息
op := service.SystemOptionsSvc{}
config, err := op.GetSystemOptions()
if err != nil {
SendJsonResponse(c, err, nil)
return
}
// TODO STEP2 用户和ip没有加入到访问规则登录不上提醒
if config.AccessRuleState == 1 {
ip := util.RemoteIp(c.Request)
svc := service.AccessRuleSvc{}
if errCode := svc.CheckIp(ip, userInfo.Id); errCode != nil {
SendJsonResponse(c, errCode, nil)
return
}
}
// TODO STEP3 密码强弱提醒
// 密码强弱提醒
if config.ForceUpdateState == 1 && config.MinPwdLevel > userInfo.PwdLevel {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("密码强度弱,请联系管理员修改密码!")), nil)
return
}
// TODO STEP4 验证码正确性校验
exist, err := loginInf.VerifyPhoneCode(req.Phone)
if err != nil {
SendJsonResponse(c, resp.FAIL.ErrorDetail(err), nil)
return
}
if exist != 1 {
SendJsonResponse(c, resp.FAIL.ErrorDetail(errors.New("验证码无效")), nil)
return
}
lastLogin, msg, uuidStr, err := loginInf.UserPhoneLogin(req, userInfo)
if err != nil {
SendJsonResponse(c, err, nil)
return
}
c.SetCookie(conf.CookieName, uuidStr, 1*60*60*24, "/", "", false, false)
c.SetCookie(conf.CookieNameLastLogin, lastLogin, 1*60*60*24, "/", "", false, false)
header.AddUserLoginLog("登入", "phone/login", constant.OpTypeIntMap[constant.Login], c, userInfo)
SendJsonResponse(c, resp.OK, msg)
}
// 根据手机号获取账户
func PhoneToAccount(c *gin.Context) {
phone := c.Query("phone")
if !util.CheckMobile(phone) {
SendJsonResponse(c, errors.New("手机号不合法!"), nil)
return
}
loginInf := service.UserSvc{}
data, err := loginInf.PhoneToAccount(phone)
if err != nil {
SendJsonResponse(c, err, nil)
return
}
SendJsonResponse(c, resp.OK, data)
}
// 验证码校验
func ForgetPwdCheck(c *gin.Context) {
req := request.ForgetPwdCheck{}
err := c.BindJSON(&req)
if err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), nil)
return
}
if err := vd.Validate(req); err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), "")
return
}
loginInf := service.UserSvc{}
err = loginInf.ForgetPwdCheck(req)
if err != nil {
SendJsonResponse(c, err, nil)
return
}
SendJsonResponse(c, resp.OK, nil)
}
// 忘记密码
func UpdateAccountPwd(c *gin.Context) {
req := request.AccountForgetPasswordReq{}
err := c.BindJSON(&req)
if err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), nil)
return
}
if err := vd.Validate(req); err != nil {
SendJsonResponse(c, resp.InvalidParam.ErrorDetail(err), "")
return
}
loginInf := service.UserSvc{}
err = loginInf.UpdateAccountPwd(req)
if err != nil {
SendJsonResponse(c, err, nil)
return
}
SendJsonResponse(c, resp.OK, nil)
}
......@@ -79,6 +79,10 @@ func initConfig() {
LocationKey: util.SetEnvStr("LOCATION_KEY", "QKFBZ-PGGWJ-VZQFF-FHPA7-QWT5H-YHF4T"),
PrivateKeySSH: util.SetEnvStr("PRIVATE_KEY_SSH", "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn\nNhAAAAAwEAAQAAAIEAsOFk9OUB8wg9fd+PDHyX8nEtTSPSZY+tjxq2da1Pf5FkIn+U1da6\nh2eqowF9lnyvlt7uEledTIWQZDGWToGYCZnRommSZEpo/vII+l1P28bJVHfgWFCqmxNfIB\nZFQ4KrOp9rXKidmrd8flhK/NTLJNqryrhhIiDs3CTyAliscIsAAAIQTuM2gU7jNoEAAAAH\nc3NoLXJzYQAAAIEAsOFk9OUB8wg9fd+PDHyX8nEtTSPSZY+tjxq2da1Pf5FkIn+U1da6h2\neqowF9lnyvlt7uEledTIWQZDGWToGYCZnRommSZEpo/vII+l1P28bJVHfgWFCqmxNfIBZF\nQ4KrOp9rXKidmrd8flhK/NTLJNqryrhhIiDs3CTyAliscIsAAAADAQABAAAAgDjcfGPtqq\n7CG2J3l7jf5MjfcTy3I0/a3GSApd82k7PivVoJwYLswJH+1XAJbqIN+zR4/fePitWqqjxL\nZJJgPstuXpBZuJDvGwMqfl7wHRL2Qx34sRG02hG5e3uIfMxe5lHcPba0qsVQt+vOhu9MUb\nsYF/mfuQJKt/Oi8nA1BbrBAAAAQFQPrap7AtYWEoCIY7gtpFMW51iDTAv5GN99DsKNuBby\nwQX2S0Wg/da75m/emJn/2IbmaKApvrx8LbenpyywfBkAAABBAN6xiYQ2j7eRjLV4h4Hbie\nVwlPYP4otKHdF5meObr+2ifYiMktdv/44V1XWKhgavjGFNWx2sHgj7byb51e/bi3MAAABB\nAMtVxa55G0wS9Yw1WK2F4JdYZ65ZAnUuo2rbA2dMDQxsOQxgel5Ox2XmC7e0GKrO9BJKPo\nR2fHEOdm9KOmoB8IkAAAAWY2hlbnppbG9uZ0BleGFtcGxlLmNvbQECAwQF\n-----END OPENSSH PRIVATE KEY-----\n"),
PublicKeySSH: util.SetEnvStr("PUBLIC_KEY_SSH", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCw4WT05QHzCD19348MfJfycS1NI9Jlj62PGrZ1rU9/kWQif5TV1rqHZ6qjAX2WfK+W3u4SV51MhZBkMZZOgZgJmdGiaZJkSmj+8gj6XU/bxslUd+BYUKqbE18gFkVDgqs6n2tcqJ2at3x+WEr81Msk2qvKuGEiIOzcJPICWKxwiw== chenzilong@example.com\n"),
SmsAccessKeyId: util.SetEnvStr("SMS_ACCESS_KEY", "LTAI4GBcVubRjzX7ABPcHnhB"), // 短信key
SmsAccessSecret: util.SetEnvStr("SMS_ACCESS_SECRET", "dYE2dtABFOqYtK1ijcrits0yedHkw7"), // 短信secret
SmsTemplateLogin: util.SetEnvStr("SMS_TEMPLATE_LOGIN", "SMS_212925130"), // 短信验证码模板
SmsSignName: util.SetEnvStr("SMS_SIGN_NAME", "比格数据"), // 签名
}
}
......
......@@ -11,10 +11,15 @@ import (
func InitSystemLoginRouter(e *gin.Engine) {
base := e.Group(fmt.Sprintf("%s/user", conf.Options.Prefix))
{
base.POST("/login", controller.UserLogin) // 登录
base.POST("/logout", controller.UserLogout) // 登出
base.GET("/getUserInfo", controller.GetUserInfo) // 获取用户信息
base.GET("/getCaptcha", controller.GetCaptcha) // 获取验证码
base.GET("/verifyCaptcha", controller.VerifyCaptcha) // 校验验证码
base.POST("/login", controller.UserLoginV2) // 登录
base.POST("/logout", controller.UserLogout) // 登出
base.GET("/getUserInfo", controller.GetUserInfo) // 获取用户信息
base.GET("/getCaptcha", controller.GetCaptcha) // 获取验证码
base.GET("/verifyCaptcha", controller.VerifyCaptcha) // 校验验证码
base.POST("/sms/verifyCode", controller.GetSmsVerifyCode) // 获取短信验证码(5分钟过期)
base.POST("/phone/login", controller.UserPhoneLogin) // 手机号登录
base.GET("/phoneToAccount", controller.PhoneToAccount) // 根据手机号获取账户
base.POST("/forget/pwd/check", controller.ForgetPwdCheck) // 忘记密码校验
base.POST("/update/pwd", controller.UpdateAccountPwd) // 忘记密码
}
}
......@@ -6,13 +6,16 @@ import (
"errors"
"fmt"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/tools"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/util"
"strconv"
dysmsapi "github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
"image/color"
"strings"
"time"
......@@ -37,11 +40,9 @@ func (u *UserSvc) GetUserInfo(phone string) (userInfo entity.SystemUserInfo, err
if err != nil {
return userInfo, resp.DbConnectError.ErrorDetail(err)
}
var userRole []entity.SystemUserInfo
// 查询用户
userModel := db.Table("system_user")
userModel.Join("LEFT", []string{"system_user_role", "sur"}, "sur.user_id = system_user.id")
userModel.Join("LEFT", []string{"system_role", "sr"}, "sur.role_id = sr.role_id")
userModel.Join("LEFT", []string{"system_organization", "so"}, "so.organization_id = system_user.organization_id")
userModel.Select("system_user.*,so.name as org_name")
if phone == "" {
......@@ -49,15 +50,11 @@ func (u *UserSvc) GetUserInfo(phone string) (userInfo entity.SystemUserInfo, err
} else {
userModel.Where("system_user.phone = ?", phone)
}
err = userModel.Where("system_user.state = 1").Find(&userRole)
_, err = userModel.Where("system_user.state = 1").Get(&userInfo)
if err != nil {
return userInfo, resp.DbSelectError.ErrorDetail(err)
}
if len(userRole) == 0 && phone == "" {
return userInfo, resp.FAIL.WithError(errors.New("该账户未启用,不能登录"))
} else if len(userRole) == 0 && phone != "" {
return userInfo, resp.FAIL.WithError(errors.New("手机号未注册!"))
}
return userInfo, nil
}
......@@ -356,15 +353,15 @@ func (u *UserSvc) LoginV2(userInfo entity.SystemUserInfo) (last_login_time, msg
}
msg = "登录成功"
conf.Logger.Info("登录成功", zap.String("msg", msg))
//go func() {
// // 最后心跳时间
// finalHeartBeatMap := map[string]interface{}{
// "final_heartbeat_unix": time.Now().UnixNano() / 1e6,
// "final_heartbeat_flag": false,
// }
// finalHeartBeatByte, _ := json.Marshal(finalHeartBeatMap)
// redisCli.HSet(conf.FinalHeartBeatUnixKey, userInfo.Id, string(finalHeartBeatByte))
//}()
go func() {
// 最后心跳时间
finalHeartBeatMap := map[string]interface{}{
"final_heartbeat_unix": time.Now().UnixNano() / 1e6,
"final_heartbeat_flag": false,
}
finalHeartBeatByte, _ := json.Marshal(finalHeartBeatMap)
redisCli.HSet(conf.FinalHeartBeatUnixKey, strconv.Itoa(userInfo.Id), string(finalHeartBeatByte))
}()
return
}
......@@ -419,3 +416,167 @@ func (u *UserSvc) SaveUserInfo(userInfo entity.SystemUserInfo, r client.Redis) (
}
return last_login, uuidStr, nil
}
// 获取短信验证码
func (u *UserSvc) GetSmsVerifyCode(phone string) (data interface{}, err error) {
smsClient, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", conf.Options.SmsAccessKeyId, conf.Options.SmsAccessSecret)
if err != nil {
conf.Logger.Error("dysmsapi client error", zap.Error(err))
return nil, resp.FAIL.ErrorDetail(err)
}
code := util.Rand6()
params := map[string]interface{}{"code": code}
templateParam, err := json.Marshal(params)
if err != nil {
conf.Logger.Error("序列化模板失败!", zap.Error(err))
return nil, resp.FAIL.ErrorDetail(err)
}
request := dysmsapi.CreateSendSmsRequest()
request.Scheme = "https"
request.PhoneNumbers = phone
request.TemplateCode = conf.Options.SmsTemplateLogin
request.SignName = conf.Options.SmsSignName
request.TemplateParam = string(templateParam)
req, err := smsClient.SendSms(request)
if err != nil {
return nil, resp.FAIL.ErrorDetail(err)
}
data, err = u.SetCodeToRedis(phone, code)
if err != nil {
conf.Logger.Error("set to cache is error!", zap.Error(err))
return nil, resp.FAIL.ErrorDetail(err)
}
fmt.Printf("response is %#v\n", req)
return data, nil
}
// 验证码保存
func (u *UserSvc) SetCodeToRedis(phone, code string) (data interface{}, err error) {
rcon, err := client.GetRedisClient()
if err != nil {
return nil, resp.RedisConnectError.ErrorDetail(err)
}
err = rcon.Set(phone, code, time.Minute*5)
if err != nil {
return nil, resp.DbInsertError.ErrorDetail(err)
}
str, err := rcon.Get(phone)
if err != nil {
return nil, resp.RedisExecError.ErrorDetail(err)
}
return str, nil
}
// 校验验证码是否过期
func (u *UserSvc) VerifyLoginCodeExpire(phone, code string, redisCli client.Redis) error {
str, err := redisCli.Get(phone)
if err != nil {
conf.Logger.Error("code不存在!")
}
if str != code {
return errors.New("验证码无效!")
}
return nil
}
func (u *UserSvc) VerifyPhoneCode(phone string) (exist int64, err error) {
rcon, err := client.GetRedisClient()
if err != nil {
return 0, err
}
exist, err = rcon.Exist(phone)
if err != nil {
return 0, err
}
return exist, nil
}
// 手机号登录
func (u *UserSvc) UserPhoneLogin(req request.SendPhoneMsg, userInfo entity.SystemUserInfo) (last_login_time, msg string, uuidStr string, err error) {
redisCli, err := client.GetRedisClient()
if err != nil {
return "", "", "", resp.RedisConnectError.ErrorDetail(err)
}
// TODO 用户数据、登录时间存入redis
last_login_time, uuidStr, err = u.SaveUserInfo(userInfo, redisCli)
if err != nil {
conf.Logger.Error("保存用户数据失败", zap.Error(err))
return "", "", "", resp.RedisExecError.ErrorDetail(err)
}
msg = "登录成功"
conf.Logger.Info("登录成功", zap.String("msg", msg))
// 登录成功,清除验证码
go func() {
// 最后心跳时间
finalHeartBeatMap := map[string]interface{}{
"final_heartbeat_unix": time.Now().UnixNano() / 1e6,
"final_heartbeat_flag": false,
}
finalHeartBeatByte, _ := json.Marshal(finalHeartBeatMap)
redisCli.HSet(conf.FinalHeartBeatUnixKey, strconv.Itoa(userInfo.Id), string(finalHeartBeatByte))
redisCli.Del(req.Phone)
}()
return
}
// 根据手机号获取账户
func (u *UserSvc) PhoneToAccount(phone string) (data string, err error) {
db, err := client.GetDbClient()
if err != nil {
err = resp.DbConnectError.ErrorDetail(err)
return
}
systemUser := entity.SystemUser{}
_, err = db.Table("system_user").Select("system_account").Where("phone = ?", phone).Get(&systemUser)
if err != nil {
conf.Logger.Error("获取账号信息失败", zap.Error(err))
return "", resp.DbSelectError.ErrorDetail(err)
}
return systemUser.SystemAccount, nil
}
func (u *UserSvc) ForgetPwdCheck(req request.ForgetPwdCheck) (err error) {
rcon, err := client.GetRedisClient()
if err != nil {
return resp.RedisConnectError.ErrorDetail(err)
}
str, err := rcon.Get(req.Phone)
if err != nil {
return resp.RedisExecError.ErrorDetail(err)
}
if str != req.Code {
return resp.FAIL.ErrorDetail(errors.New("验证码不正确"))
}
return
}
func (u *UserSvc) UpdateAccountPwd(req request.AccountForgetPasswordReq) (err error) {
db, err := client.GetDbClient()
if err != nil {
err = resp.DbConnectError.ErrorDetail(err)
return
}
oldSystemUser := entity.SystemUser{}
has, err := db.Cols("password", "id").Where("phone = ?", req.Phone).Get(&oldSystemUser)
if err != nil || !has {
conf.Logger.Error("查询系统账户详情失败", zap.Error(err))
err = resp.DbSelectError.ErrorDetail(errors.New("查询系统账户详情失败"))
return
}
password, err := SolvePassword(oldSystemUser.Id, req.Password)
if err != nil {
return
}
SystemUser := entity.SystemUser{}
SystemUser.Password = password
SystemUser.PwdForceStatus = 0
SystemUser.PwdUpdatedTime = time.Now()
_, err = db.Where("id =?", oldSystemUser.Id).Where("is_deleted = 0").Cols("password", "pwd_force_status", "pwd_updated_time").Update(&SystemUser)
if err != nil {
conf.Logger.Error("修改系统账户失败", zap.Error(err))
err = resp.DbUpdateError.ErrorDetail(errors.New("修改系统账户失败"))
return
}
return
}
......@@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf"
"math/rand"
"net/http"
"regexp"
"strings"
......@@ -151,3 +152,15 @@ func SubDays(t1, t2 time.Time) (day int) {
}
return
}
// CheckMobile 检验手机号
func CheckMobile(phone string) bool {
regRuler := "^1[345789]{1}\\d{9}$"
reg := regexp.MustCompile(regRuler)
return reg.MatchString(phone)
}
// Rand6 生成一个6位随机数字
func Rand6() string {
return fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment