This commit is contained in:
		| @@ -23,7 +23,7 @@ func VerifyToken(authorization string) error { | |||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewToken(auds ...string) (string, error) { | func NewToken(expire time.Duration, auds ...string) (string, error) { | ||||||
| 	if len(auds) == 0 { | 	if len(auds) == 0 { | ||||||
| 		auds = []string{"non-audience"} | 		auds = []string{"non-audience"} | ||||||
| 	} | 	} | ||||||
| @@ -32,7 +32,7 @@ func NewToken(auds ...string) (string, error) { | |||||||
| 		"bar", | 		"bar", | ||||||
| 		jwt.RegisteredClaims{ | 		jwt.RegisteredClaims{ | ||||||
| 			// A usual scenario is to set the expiration time relative to the current time | 			// 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()), | 			IssuedAt:  jwt.NewNumericDate(time.Now()), | ||||||
| 			NotBefore: jwt.NewNumericDate(time.Now()), | 			NotBefore: jwt.NewNumericDate(time.Now()), | ||||||
| 			Issuer:    "drivelinked", | 			Issuer:    "drivelinked", | ||||||
| @@ -48,3 +48,11 @@ func NewToken(auds ...string) (string, error) { | |||||||
| 	} | 	} | ||||||
| 	return ss, nil | 	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) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -47,3 +47,8 @@ func (r *Response) ErrBadRequest() { | |||||||
| func (r *Response) ErrUnauthorized() { | func (r *Response) ErrUnauthorized() { | ||||||
| 	r.Error(http.StatusUnauthorized, "未登录") | 	r.Error(http.StatusUnauthorized, "未登录") | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 账号或密码错误 | ||||||
|  | func (r *Response) ErrBadAccPasswd() { | ||||||
|  | 	r.Error(serializer.ErrBadLogin, "账号或密码错误") | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package dto | package dto | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"drive-linked/model" | 	"drive-linked/pkg/model" | ||||||
| 	"github.com/jinzhu/copier" | 	"github.com/jinzhu/copier" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -15,11 +15,6 @@ type UserProfile struct { | |||||||
| 	Roles    string `json:"roles"` | 	Roles    string `json:"roles"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type QueryUserParams struct { |  | ||||||
| 	Method string `json:"method"` |  | ||||||
| 	Value  string `json:"value"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (u *UserProfile) CopyOf(user *model.User) error { | func (u *UserProfile) CopyOf(user *model.User) error { | ||||||
| 	err := copier.Copy(u, user) | 	err := copier.Copy(u, user) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -27,3 +22,13 @@ func (u *UserProfile) CopyOf(user *model.User) error { | |||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type QueryUserParams struct { | ||||||
|  | 	Method string `json:"method"` | ||||||
|  | 	Value  string `json:"value"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type LoginParams struct { | ||||||
|  | 	Account  string `json:"account"` | ||||||
|  | 	Password string `json:"password"` | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								pkg/model/login.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								pkg/model/login.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
| @@ -8,7 +8,7 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type User struct { | type User struct { | ||||||
| 	Id       int64  `json:"id,string"` | 	ID       int64  `json:"id,string"` | ||||||
| 	Name     string `json:"name"` | 	Name     string `json:"name"` | ||||||
| 	Nickname string `json:"nickname"` | 	Nickname string `json:"nickname"` | ||||||
| 	Email    string `json:"email"` | 	Email    string `json:"email"` | ||||||
| @@ -18,7 +18,7 @@ type User struct { | |||||||
| 	Roles    string `json:"roles"` | 	Roles    string `json:"roles"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (user *User) GetWithConditions(conditions *map[string]interface{}) error { | func (user *User) GetProfileWithConditions(conditions *map[string]interface{}) error { | ||||||
| 	// 支持多条件查询 | 	// 支持多条件查询 | ||||||
| 	//TODO:分离多条件查询部分,有利于代码复用 | 	//TODO:分离多条件查询部分,有利于代码复用 | ||||||
| 	var where []string | 	var where []string | ||||||
| @@ -29,7 +29,7 @@ func (user *User) GetWithConditions(conditions *map[string]interface{}) error { | |||||||
| 		where = append(where, fmt.Sprintf(`"%s" = %s`, k, "?")) | 		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...) | 	err := dao.DB.Get(user, exec, values...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -14,7 +14,7 @@ func TestUser_GetWithConditions(t *testing.T) { | |||||||
| 		"name":  "eigeen", | 		"name":  "eigeen", | ||||||
| 		"email": "375109735@qq.com", | 		"email": "375109735@qq.com", | ||||||
| 	} | 	} | ||||||
| 	err := user.GetWithConditions(conditions) | 	err := user.GetProfileWithConditions(conditions) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Error(err) | 		t.Error(err) | ||||||
| 	} | 	} | ||||||
							
								
								
									
										6
									
								
								pkg/serializer/login.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pkg/serializer/login.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | package serializer | ||||||
|  |  | ||||||
|  | type LoginResponse struct { | ||||||
|  | 	Token        string `json:"token"` | ||||||
|  | 	RefreshToken string `json:"refresh_token"` | ||||||
|  | } | ||||||
| @@ -13,4 +13,5 @@ type ResponseSerial struct { | |||||||
| */ | */ | ||||||
| const ( | const ( | ||||||
| 	ErrNoUser   = 40001 | 	ErrNoUser   = 40001 | ||||||
|  | 	ErrBadLogin = 40002 | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -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() |  | ||||||
| } |  | ||||||
| @@ -2,11 +2,14 @@ package service | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"database/sql" | 	"database/sql" | ||||||
| 	"drive-linked/model" | 	"drive-linked/pkg/common" | ||||||
| 	"drive-linked/pkg/dto" | 	"drive-linked/pkg/dto" | ||||||
|  | 	"drive-linked/pkg/model" | ||||||
| 	"drive-linked/pkg/serializer" | 	"drive-linked/pkg/serializer" | ||||||
|  | 	"drive-linked/pkg/utils" | ||||||
| 	"github.com/kataras/iris/v12" | 	"github.com/kataras/iris/v12" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"regexp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type UsersService struct { | type UsersService struct { | ||||||
| @@ -26,7 +29,7 @@ func (serv *UsersService) GetOneUser(conditions *map[string]interface{}) { | |||||||
| 	resp := dto.NewResponse(serv.Ctx) | 	resp := dto.NewResponse(serv.Ctx) | ||||||
| 	user := &model.User{} | 	user := &model.User{} | ||||||
|  |  | ||||||
| 	err = user.GetWithConditions(conditions) | 	err = user.GetProfileWithConditions(conditions) | ||||||
|  |  | ||||||
| 	switch err { | 	switch err { | ||||||
| 	case nil: | 	case nil: | ||||||
| @@ -38,7 +41,46 @@ func (serv *UsersService) GetOneUser(conditions *map[string]interface{}) { | |||||||
| 		} | 		} | ||||||
| 		resp.Success(userResult) | 		resp.Success(userResult) | ||||||
| 	case sql.ErrNoRows: | 	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: | 	default: | ||||||
| 		resp.Error(http.StatusInternalServerError, "获取用户信息失败,数据库异常") | 		resp.Error(http.StatusInternalServerError, "获取用户信息失败,数据库异常") | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -12,8 +12,8 @@ func GenPasswd(originPasswd string) (passwd string, err error) { | |||||||
| 	return passwd, nil | 	return passwd, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func CheckPasswd(originPasswd string, passwd string) (match bool, err error) { | func CheckPasswd(password string, hash string) (match bool, err error) { | ||||||
| 	match, err = argon2id.ComparePasswordAndHash(originPasswd, passwd) | 	match, err = argon2id.ComparePasswordAndHash(password, hash) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								router/controller/usersController.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								router/controller/usersController.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | } | ||||||
| @@ -2,8 +2,9 @@ package router | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"drive-linked/pkg/middleware" | 	"drive-linked/pkg/middleware" | ||||||
| 	"drive-linked/pkg/service/controller" | 	"drive-linked/router/controller" | ||||||
| 	"github.com/kataras/iris/v12" | 	"github.com/kataras/iris/v12" | ||||||
|  | 	"github.com/kataras/iris/v12/core/router" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Router() *iris.Application { | func Router() *iris.Application { | ||||||
| @@ -16,6 +17,9 @@ func Router() *iris.Application { | |||||||
| 	// 注册路由 | 	// 注册路由 | ||||||
| 	// v1 | 	// v1 | ||||||
| 	v1 := app.Party("/v1") | 	v1 := app.Party("/v1") | ||||||
|  | 	v1.PartyFunc("/auth", func(auth router.Party) { | ||||||
|  | 		auth.Post("/login", controller.UserLogin) | ||||||
|  | 	}) | ||||||
| 	v1.PartyFunc("/users", func(users iris.Party) { | 	v1.PartyFunc("/users", func(users iris.Party) { | ||||||
| 		// 需要登录 | 		// 需要登录 | ||||||
| 		users.Use(middleware.SignRequired) | 		users.Use(middleware.SignRequired) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user