From 35801f5ee92c6d3785f97577b26e13dce7a92cbc Mon Sep 17 00:00:00 2001 From: Eigeen Date: Sat, 9 Apr 2022 11:48:44 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:Feat:=20=E7=99=BB=E5=BD=95=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/common/token.go | 12 +++++- pkg/dto/response.go | 5 +++ pkg/dto/user.go | 17 +++++--- pkg/model/login.go | 27 +++++++++++++ {model => pkg/model}/user.go | 6 +-- {model => pkg/model}/user_test.go | 2 +- pkg/serializer/login.go | 6 +++ pkg/serializer/response.go | 3 +- pkg/service/controller/usersController.go | 20 ---------- pkg/service/users.go | 48 +++++++++++++++++++++-- pkg/utils/password.go | 4 +- router/controller/usersController.go | 43 ++++++++++++++++++++ router/router.go | 6 ++- 13 files changed, 160 insertions(+), 39 deletions(-) create mode 100644 pkg/model/login.go rename {model => pkg/model}/user.go (79%) rename {model => pkg/model}/user_test.go (85%) create mode 100644 pkg/serializer/login.go delete mode 100644 pkg/service/controller/usersController.go create mode 100644 router/controller/usersController.go diff --git a/pkg/common/token.go b/pkg/common/token.go index 01a4268..4465c8c 100644 --- a/pkg/common/token.go +++ b/pkg/common/token.go @@ -23,7 +23,7 @@ func VerifyToken(authorization string) error { return err } -func NewToken(auds ...string) (string, error) { +func NewToken(expire time.Duration, auds ...string) (string, error) { if len(auds) == 0 { auds = []string{"non-audience"} } @@ -32,7 +32,7 @@ func NewToken(auds ...string) (string, error) { "bar", jwt.RegisteredClaims{ // A usual scenario is to set the expiration time relative to the current time - ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(config.Cfg.Security.Jwt.Expire) * time.Second)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(expire)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: "drivelinked", @@ -48,3 +48,11 @@ func NewToken(auds ...string) (string, error) { } return ss, nil } + +func NewShortToken(auds ...string) (string, error) { + return NewToken(time.Duration(config.Cfg.Security.Jwt.Expire) * time.Second) +} + +func NewRefreshToken(auds ...string) (string, error) { + return NewToken(24 * time.Hour) +} diff --git a/pkg/dto/response.go b/pkg/dto/response.go index 5f31802..430078c 100644 --- a/pkg/dto/response.go +++ b/pkg/dto/response.go @@ -47,3 +47,8 @@ func (r *Response) ErrBadRequest() { func (r *Response) ErrUnauthorized() { r.Error(http.StatusUnauthorized, "未登录") } + +// 账号或密码错误 +func (r *Response) ErrBadAccPasswd() { + r.Error(serializer.ErrBadLogin, "账号或密码错误") +} diff --git a/pkg/dto/user.go b/pkg/dto/user.go index 3af2339..9693056 100644 --- a/pkg/dto/user.go +++ b/pkg/dto/user.go @@ -1,7 +1,7 @@ package dto import ( - "drive-linked/model" + "drive-linked/pkg/model" "github.com/jinzhu/copier" ) @@ -15,11 +15,6 @@ type UserProfile struct { Roles string `json:"roles"` } -type QueryUserParams struct { - Method string `json:"method"` - Value string `json:"value"` -} - func (u *UserProfile) CopyOf(user *model.User) error { err := copier.Copy(u, user) if err != nil { @@ -27,3 +22,13 @@ func (u *UserProfile) CopyOf(user *model.User) error { } return nil } + +type QueryUserParams struct { + Method string `json:"method"` + Value string `json:"value"` +} + +type LoginParams struct { + Account string `json:"account"` + Password string `json:"password"` +} diff --git a/pkg/model/login.go b/pkg/model/login.go new file mode 100644 index 0000000..f5794db --- /dev/null +++ b/pkg/model/login.go @@ -0,0 +1,27 @@ +package model + +import ( + "drive-linked/pkg/dao" + "fmt" +) + +const ( + LoginMethodName = "name" + LoginMethodEmail = "email" +) + +type Login struct { + ID int64 + Name string + Password string +} + +func (u *Login) GetLoginInfo(account, method string) error { + exec := fmt.Sprintf(`SELECT id, name, password FROM users WHERE %s=?`, method) + + err := dao.DB.Get(u, exec, account) + if err != nil { + return err + } + return nil +} diff --git a/model/user.go b/pkg/model/user.go similarity index 79% rename from model/user.go rename to pkg/model/user.go index 4a00262..91f0ece 100644 --- a/model/user.go +++ b/pkg/model/user.go @@ -8,7 +8,7 @@ import ( ) type User struct { - Id int64 `json:"id,string"` + ID int64 `json:"id,string"` Name string `json:"name"` Nickname string `json:"nickname"` Email string `json:"email"` @@ -18,7 +18,7 @@ type User struct { Roles string `json:"roles"` } -func (user *User) GetWithConditions(conditions *map[string]interface{}) error { +func (user *User) GetProfileWithConditions(conditions *map[string]interface{}) error { // 支持多条件查询 //TODO:分离多条件查询部分,有利于代码复用 var where []string @@ -29,7 +29,7 @@ func (user *User) GetWithConditions(conditions *map[string]interface{}) error { where = append(where, fmt.Sprintf(`"%s" = %s`, k, "?")) } - exec := sqlx.Rebind(sqlx.QUESTION, `SELECT * FROM users WHERE `+strings.Join(where, "AND")+" LIMIT 1") + exec := sqlx.Rebind(sqlx.QUESTION, "SELECT * FROM users WHERE "+strings.Join(where, "AND")+" LIMIT 1") err := dao.DB.Get(user, exec, values...) if err != nil { return err diff --git a/model/user_test.go b/pkg/model/user_test.go similarity index 85% rename from model/user_test.go rename to pkg/model/user_test.go index 0acd68f..3890207 100644 --- a/model/user_test.go +++ b/pkg/model/user_test.go @@ -14,7 +14,7 @@ func TestUser_GetWithConditions(t *testing.T) { "name": "eigeen", "email": "375109735@qq.com", } - err := user.GetWithConditions(conditions) + err := user.GetProfileWithConditions(conditions) if err != nil { t.Error(err) } diff --git a/pkg/serializer/login.go b/pkg/serializer/login.go new file mode 100644 index 0000000..5be359f --- /dev/null +++ b/pkg/serializer/login.go @@ -0,0 +1,6 @@ +package serializer + +type LoginResponse struct { + Token string `json:"token"` + RefreshToken string `json:"refresh_token"` +} diff --git a/pkg/serializer/response.go b/pkg/serializer/response.go index 092ef14..775cee7 100644 --- a/pkg/serializer/response.go +++ b/pkg/serializer/response.go @@ -12,5 +12,6 @@ type ResponseSerial struct { 50000 服务器操作 */ const ( - ErrNoUser = 40001 + ErrNoUser = 40001 + ErrBadLogin = 40002 ) diff --git a/pkg/service/controller/usersController.go b/pkg/service/controller/usersController.go deleted file mode 100644 index 46994eb..0000000 --- a/pkg/service/controller/usersController.go +++ /dev/null @@ -1,20 +0,0 @@ -package controller - -import ( - "drive-linked/pkg/service" - "github.com/kataras/iris/v12" -) - -func UserProfile(ctx iris.Context) { - serv := service.NewUsersService(ctx) - - // 获取所有查询条件参数 - var conditions map[string]interface{} - for _, field := range service.UserConditions { - if ctx.Params().GetString(field) != "" { - conditions[field] = ctx.Params().GetString(field) - } - } - serv.GetOneUser(&conditions) - ctx.Next() -} diff --git a/pkg/service/users.go b/pkg/service/users.go index 319442b..ba84168 100644 --- a/pkg/service/users.go +++ b/pkg/service/users.go @@ -2,11 +2,14 @@ package service import ( "database/sql" - "drive-linked/model" + "drive-linked/pkg/common" "drive-linked/pkg/dto" + "drive-linked/pkg/model" "drive-linked/pkg/serializer" + "drive-linked/pkg/utils" "github.com/kataras/iris/v12" "net/http" + "regexp" ) type UsersService struct { @@ -26,7 +29,7 @@ func (serv *UsersService) GetOneUser(conditions *map[string]interface{}) { resp := dto.NewResponse(serv.Ctx) user := &model.User{} - err = user.GetWithConditions(conditions) + err = user.GetProfileWithConditions(conditions) switch err { case nil: @@ -38,7 +41,46 @@ func (serv *UsersService) GetOneUser(conditions *map[string]interface{}) { } resp.Success(userResult) case sql.ErrNoRows: - resp.Error(serializer.ErrNoUser, "找不到此用户") + resp.Error(serializer.ErrNoUser, "用户不存在") + default: + resp.Error(http.StatusInternalServerError, "获取用户信息失败,数据库异常") + } +} + +func (serv *UsersService) Login(loginParams dto.LoginParams) { + var err error + resp := dto.NewResponse(serv.Ctx) + + // 登录逻辑 + // 判断账号类型 邮箱/用户名 + var method string + emailExp := regexp.MustCompile("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") + if emailExp.Match([]byte(loginParams.Account)) { + method = model.LoginMethodEmail + } else { + method = model.LoginMethodName + } + + // 从数据库取出原密码 + userLogin := model.Login{} + err = userLogin.GetLoginInfo(loginParams.Account, method) + switch err { + case nil: + // 检查密码 + match, _ := utils.CheckPasswd(loginParams.Password, userLogin.Password) + if match { + // 登录成功,签发token + sToken, _ := common.NewShortToken(userLogin.Name) + rToken, _ := common.NewRefreshToken(userLogin.Name) + resp.Success(serializer.LoginResponse{ + Token: sToken, + RefreshToken: rToken, + }) + } else { + resp.ErrBadAccPasswd() + } + case sql.ErrNoRows: + resp.Error(serializer.ErrNoUser, "用户不存在") default: resp.Error(http.StatusInternalServerError, "获取用户信息失败,数据库异常") } diff --git a/pkg/utils/password.go b/pkg/utils/password.go index 5621971..b1e3053 100644 --- a/pkg/utils/password.go +++ b/pkg/utils/password.go @@ -12,8 +12,8 @@ func GenPasswd(originPasswd string) (passwd string, err error) { return passwd, nil } -func CheckPasswd(originPasswd string, passwd string) (match bool, err error) { - match, err = argon2id.ComparePasswordAndHash(originPasswd, passwd) +func CheckPasswd(password string, hash string) (match bool, err error) { + match, err = argon2id.ComparePasswordAndHash(password, hash) if err != nil { return false, err } diff --git a/router/controller/usersController.go b/router/controller/usersController.go new file mode 100644 index 0000000..2f96040 --- /dev/null +++ b/router/controller/usersController.go @@ -0,0 +1,43 @@ +package controller + +import ( + "drive-linked/pkg/dto" + "drive-linked/pkg/service" + "encoding/json" + "github.com/kataras/iris/v12" +) + +func UserProfile(ctx iris.Context) { + serv := service.NewUsersService(ctx) + resp := dto.NewResponse(ctx) + + // 获取所有查询条件参数 + conditions := make(map[string]interface{}) + for _, field := range service.UserConditions { + if ctx.URLParam(field) != "" { + conditions[field] = ctx.URLParam(field) + } + } + + if len(conditions) == 0 { + resp.ErrBadRequest() + return + } + + serv.GetOneUser(&conditions) +} + +func UserLogin(ctx iris.Context) { + serv := service.NewUsersService(ctx) + resp := dto.NewResponse(ctx) + var loginParams dto.LoginParams + + // 转换参数 + body, _ := ctx.GetBody() + err := json.Unmarshal(body, &loginParams) + if err != nil { + resp.ErrBadRequest() + } + + serv.Login(loginParams) +} diff --git a/router/router.go b/router/router.go index ccfe3f3..6e7b513 100644 --- a/router/router.go +++ b/router/router.go @@ -2,8 +2,9 @@ package router import ( "drive-linked/pkg/middleware" - "drive-linked/pkg/service/controller" + "drive-linked/router/controller" "github.com/kataras/iris/v12" + "github.com/kataras/iris/v12/core/router" ) func Router() *iris.Application { @@ -16,6 +17,9 @@ func Router() *iris.Application { // 注册路由 // v1 v1 := app.Party("/v1") + v1.PartyFunc("/auth", func(auth router.Party) { + auth.Post("/login", controller.UserLogin) + }) v1.PartyFunc("/users", func(users iris.Party) { // 需要登录 users.Use(middleware.SignRequired)