From b876eab301fc6cddb315cfd0dc446b1221fef5d9 Mon Sep 17 00:00:00 2001 From: henry Date: Tue, 28 Sep 2021 18:23:34 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AE=8C=E5=96=84=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- app/common/api/api.go | 99 +++++++++++++++++ app/common/model/sys_sms.go | 4 + app/common/model/tenant_user.go | 21 ++++ app/enterprise/README.md | 6 + app/enterprise/api/account.go | 45 ++++++++ app/enterprise/controller/account/login.go | 121 +++++++++++++++++++++ app/enterprise/model/tenant_user.go | 19 ++++ config.yaml | 4 +- 9 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 app/common/api/api.go create mode 100644 app/common/model/sys_sms.go create mode 100644 app/common/model/tenant_user.go create mode 100644 app/enterprise/README.md create mode 100644 app/enterprise/api/account.go create mode 100644 app/enterprise/controller/account/login.go create mode 100644 app/enterprise/model/tenant_user.go diff --git a/README.md b/README.md index e4a28ed..3eeab4d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# IOT +# SciencesServer -物联网服务 \ No newline at end of file +中科元系统管理 \ No newline at end of file diff --git a/app/common/api/api.go b/app/common/api/api.go new file mode 100644 index 0000000..6ac5ad3 --- /dev/null +++ b/app/common/api/api.go @@ -0,0 +1,99 @@ +package api + +import ( + "SciencesServer/config" + "SciencesServer/serve/logger" + "SciencesServer/utils" + "errors" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "net/http" +) + +const ( + SuccessCode = 200 //成功的状态码 + FailureCode = 999 //失败的状态码 +) + +type response struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} + +type ApiHandle func(c *gin.Context) interface{} + +func GetSession() ApiHandle { + return func(c *gin.Context) interface{} { + value, _ := c.Get(config.TokenForSession) + return value + } +} + +func Bind(req interface{}) ApiHandle { + return func(c *gin.Context) interface{} { + var err error + + if c.Request.Method == "GET" { + err = c.ShouldBindQuery(req) + } else { + err = c.ShouldBindBodyWith(req, binding.JSON) + } + if err != nil { + logger.ErrorF("Request URL【%s】Params Bind Error:%v", c.Request.URL, err) + return errors.New("参数异常/缺失") + } + c.Set("params", utils.AnyToJSON(req)) + return nil + } +} + +func APISuccess(data ...interface{}) ApiHandle { + return func(c *gin.Context) interface{} { + resp := &response{ + Code: SuccessCode, + Message: "ok", + } + if len(data) > 0 { + resp.Data = data[0] + } + c.JSON(http.StatusOK, resp) + return nil + } +} + +func APIFailure(err error) ApiHandle { + return func(c *gin.Context) interface{} { + resp := &response{ + Code: FailureCode, + Message: "failure", + } + if err != nil { + resp.Message = err.Error() + } + c.JSON(http.StatusOK, resp) + c.Abort() + return nil + } +} + +func APIResponse(err error, data ...interface{}) ApiHandle { + return func(c *gin.Context) interface{} { + resp := &response{ + Code: SuccessCode, + Message: "ok", + } + if err != nil { + resp.Code = FailureCode + resp.Message = err.Error() + c.JSON(http.StatusOK, resp) + c.Abort() + return nil + } + if len(data) > 0 { + resp.Data = data[0] + } + c.JSON(http.StatusOK, resp) + return nil + } +} diff --git a/app/common/model/sys_sms.go b/app/common/model/sys_sms.go new file mode 100644 index 0000000..4681791 --- /dev/null +++ b/app/common/model/sys_sms.go @@ -0,0 +1,4 @@ +package model + +type SysSms struct { +} diff --git a/app/common/model/tenant_user.go b/app/common/model/tenant_user.go new file mode 100644 index 0000000..891bb63 --- /dev/null +++ b/app/common/model/tenant_user.go @@ -0,0 +1,21 @@ +package model + +type TenantUser struct { + Model + ModelTenant + UUID uint64 `gorm:"column:uuid;uniqueIndex:idx_sys_user_uuid;type:int;default:0;comment:用户唯一UUID" json:"-"` + Avatar string `gorm:"column:avatar;type:varchar(255);default:null;comment:头像" json:"avatar"` + Name string `gorm:"column:name;type:varchar(20);default:null;comment:真实姓名" json:"name"` + Mobile string `gorm:"column:mobile;index:idx_sys_user_mobile;type:varchar(15);default:null;comment:联系方式" json:"mobile"` + Email string `gorm:"column:email;type:varchar(50);default:null;comment:邮箱" json:"email"` + ModelDeleted + ModelAt +} + +func (m *TenantUser) TableName() string { + return m.NewTableName("tenant_user") +} + +func NewTenantUser() *TenantUser { + return &TenantUser{} +} diff --git a/app/enterprise/README.md b/app/enterprise/README.md new file mode 100644 index 0000000..8d3110e --- /dev/null +++ b/app/enterprise/README.md @@ -0,0 +1,6 @@ +## 企业后台 + +- 企业后台 +- 专家后台 +- 研究机构后台 +- 实验室后台 \ No newline at end of file diff --git a/app/enterprise/api/account.go b/app/enterprise/api/account.go new file mode 100644 index 0000000..2c3445e --- /dev/null +++ b/app/enterprise/api/account.go @@ -0,0 +1,45 @@ +package api + +import ( + "SciencesServer/app/common/api" + "SciencesServer/app/enterprise/controller/account" + "github.com/gin-gonic/gin" +) + +type Account struct{} + +type ( + accountLoginForm struct { + Mode int `json:"mode" form:"mode" binding:"required"` + } + + accountRegisterForm struct { + } +) + +func (a *Account) Login(c *gin.Context) { + form := new(accountLoginForm) + + if err := api.Bind(form)(c); err != nil { + api.APIFailure(err.(error))(c) + return + } + data, err := account.NewLogin().Login()(account.LoginMode(form.Mode), nil) + api.APIResponse(err, data) +} + +func (a *Account) Register() { + +} + +func (c *Account) BindName() { + +} + +func (c *Account) BindMobile() { + +} + +func (a *Account) Logout() { + +} diff --git a/app/enterprise/controller/account/login.go b/app/enterprise/controller/account/login.go new file mode 100644 index 0000000..76b22f7 --- /dev/null +++ b/app/enterprise/controller/account/login.go @@ -0,0 +1,121 @@ +package account + +import ( + model2 "SciencesServer/app/common/model" + "SciencesServer/app/enterprise/model" + "SciencesServer/app/handle" + "SciencesServer/config" + "SciencesServer/utils" + "errors" +) + +type Login struct{} + +type ( + LoginHandle func(LoginMode, *LoginRequest) (*LoginResponse, error) +) + +type ( + LoginRequest struct { + Captcha struct { + Mobile string `json:"mobile"` + Captcha string `json:"captcha"` + } + Password struct { + Mobile string `json:"mobile"` + Password string `json:"password"` + } + Platform struct { + OpenID string `json:"open_id"` + } + } + LoginResponse struct { + Token string `json:"token"` + EffectTime int `json:"effect_time"` + } +) + +// LoginMode 登陆模式 +type LoginMode int + +const ( + LoginModeForCaptcha LoginMode = iota + 1e2 + 1 // 验证码登陆 + LoginModeForPassword // 密码登陆 + LoginModeForWechat // 微信登陆 + LoginModeForQQ // QQ登陆 +) + +var loginHandle = map[LoginMode]func(*LoginRequest) (*model.TenantUser, error){ + LoginModeForCaptcha: loginForCaptcha, LoginModeForPassword: loginForPassword, +} + +// loginForCaptcha 验证码登陆 +func loginForCaptcha(req *LoginRequest) (*model.TenantUser, error) { + pass, err := handle.NewCaptcha().Validate(&handle.CaptchaSms{ + Mobile: req.Captcha.Mobile, + Captcha: req.Captcha.Captcha, + }) + if err != nil { + return nil, err + } else if !pass { + return nil, errors.New("验证码错误或已过期") + } + var isExist bool + + mTenantUsr := model.NewTenantUser() + + if isExist, err = model2.FirstField(mTenantUsr.TenantUser, []string{"id", "name", "status"}, + model2.NewWhere("mobile", req.Captcha.Mobile)); err != nil { + return nil, err + } else if isExist { + return nil, errors.New("当前手机号码未注册") + } + return mTenantUsr, nil +} + +// loginForPassword 密码登陆 +func loginForPassword(req *LoginRequest) (*model.TenantUser, error) { + mTenantUsr := model.NewTenantUser() + + isExist, err := model2.FirstField(mTenantUsr.TenantUser, []string{"id", "name", "status"}, + model2.NewWhere("mobile", req.Password.Mobile)) + + if err != nil { + return nil, err + } else if isExist { + return nil, errors.New("当前手机号码未注册") + } + if !mTenantUsr.ValidatePassword(req.Password.Password) { + return nil, errors.New("账户或密码错误") + } + return mTenantUsr, nil +} + +func loginForPlatform(req *LoginRequest) error { + return nil +} + +func (c *Login) Login() LoginHandle { + return func(mode LoginMode, req *LoginRequest) (*LoginResponse, error) { + handle, has := loginHandle[mode] + + if !has { + return nil, errors.New("未知的登陆模式") + } + user, err := handle(req) + + if err != nil { + return nil, err + } + token := utils.JWTEncrypt(config.SettingInfo.TokenEffectTime, map[string]interface{}{ + config.TokenForUID: user.UUID, + }) + return &LoginResponse{ + Token: token, EffectTime: config.SettingInfo.TokenEffectTime, + }, nil + } +} + +func NewLogin() *Login { + return &Login{} +} diff --git a/app/enterprise/model/tenant_user.go b/app/enterprise/model/tenant_user.go new file mode 100644 index 0000000..d2635d0 --- /dev/null +++ b/app/enterprise/model/tenant_user.go @@ -0,0 +1,19 @@ +package model + +import "SciencesServer/app/common/model" + +type TenantUser struct { + *model.TenantUser +} + +func (m *TenantUser) UUIDToString() string { + return "" +} + +func (m *TenantUser) ValidatePassword(password string) bool { + return true +} + +func NewTenantUser() *TenantUser { + return &TenantUser{TenantUser: model.NewTenantUser()} +} diff --git a/config.yaml b/config.yaml index ddf6ec0..f496baa 100644 --- a/config.yaml +++ b/config.yaml @@ -7,7 +7,7 @@ token_effect_time: 604800 multiple_login: true server: - port: 8090 + port: 8000 read_timeout: 5 write_timeout: 5 idle_timeout: 5 @@ -38,7 +38,7 @@ engine: port: 3306 user: appuser password: ABCabc01! - db_name: iot_test + db_name: sciences parameters: charset=utf8mb4,utf8&parseTime=True&loc=Asia%2FShanghai # SQLITE 配置 sqlite: