diff --git a/controller/api/auth.go b/controller/api/auth.go deleted file mode 100644 index 5cc256b..0000000 --- a/controller/api/auth.go +++ /dev/null @@ -1,7 +0,0 @@ -package api - -import "github.com/gin-gonic/gin" - -func GetAuth(c *gin.Context) { - -} \ No newline at end of file diff --git a/controller/api/v1/basic/business.go b/controller/api/v1/basic/business.go index e178b07..b0f2807 100644 --- a/controller/api/v1/basic/business.go +++ b/controller/api/v1/basic/business.go @@ -16,6 +16,7 @@ import ( // @Description // @Accept json // @Produce json +// @Param Authorization header string true "auth by /auth" // @Success 200 {string} json "{"code" : 200, "data" : {}, "msg" : "ok"}" // @Router /v1/businesses [get] func GetBusinesses(c *gin.Context) { diff --git a/controller/api/v1/basic/meta_database.go b/controller/api/v1/basic/meta_database.go index 568790f..e23e4de 100644 --- a/controller/api/v1/basic/meta_database.go +++ b/controller/api/v1/basic/meta_database.go @@ -36,7 +36,7 @@ func GetMetaDatabases(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "code": code, "msg": e.GetMsg(code), - "basic": data, + "data": data, }) } diff --git a/controller/api/v1/user.go b/controller/api/v1/user.go new file mode 100644 index 0000000..8af9394 --- /dev/null +++ b/controller/api/v1/user.go @@ -0,0 +1,141 @@ +package v1 + +import ( + "github.com/astaxie/beego/validation" + "github.com/gin-gonic/gin" + "github.com/viletyy/potato/models" + "github.com/viletyy/potato/pkg/e" + "github.com/viletyy/potato/pkg/logging" + "github.com/viletyy/potato/pkg/setting" + "github.com/viletyy/potato/pkg/util" + "net/http" +) + +type user struct { + Username string `valid:"Required; MaxSize(50)"` + Password string `valid:"Required; MaxSize(50)"` +} + +// @Summary 用户验证 +// @Description +// @Accept json +// @Produce json +// @Param username query string true "用户 用户名" +// @Param password query string true "用户 密码" +// @Success 200 {string} json "{"code" : 200, "data" : {"token" : ""}, "msg" : "ok"}" +// @Router /v1/auth [get] +func GetUserAuth(c *gin.Context) { + username := c.Query("username") + password := c.Query("password") + + valid := validation.Validation{} + a := user{Username: username, Password: password} + ok, err := valid.Valid(&a) + + logging.Info(err) + + data := make(map[string]interface{}) + code := e.INVALID_PARAMS + + if ok { + isExist := models.CheckUser(username, password) + if isExist { + token, err := util.GenerateToken(username, password) + if err != nil { + code = e.ERROR_AUTH_TOKEN + } else { + data["token"] = token + code = e.SUCCESS + } + } else { + code = e.ERROR_AUTH + } + } else { + for _, err := range valid.Errors { + logging.Info(err.Key, err.Message) + } + } + + c.JSON(http.StatusOK, gin.H{ + "code" : code, + "msg" : e.GetMsg(code), + "data" : data, + }) +} + +// @Summary 用户列表 +// @Tags users +// @Description +// @Accept json +// @Produce json +// @Success 200 {string} json "{"code" : 200, "data" : {}, "msg" : "ok"}" +// @Router /v1/users [get] +func GetUsers(c *gin.Context) { + username := c.Query("username") + nickname := c.Query("nickname") + + maps := make(map[string]interface{}) + data := make(map[string]interface{}) + + if username != "" { + maps["username"] = username + } + if nickname != "" { + maps["nickname"] = nickname + } + + data["lists"] = models.GetUsers(util.GetPage(c), setting.PageSize, maps) + data["total"] = models.GetUsersTotal(maps) + code := e.SUCCESS + + c.JSON(http.StatusOK, gin.H{ + "code" : code, + "msg" : e.GetMsg(code), + "data" : data, + }) +} + +// @Summary 新增用户 +// @Tags users +// @Description +// @Accept mpfd +// @Produce json +// @Param username formData string true "用户 用户名" +// @Param password formData string true "用户 密码" +// @Param nickname formData string true "用户 真实姓名" +// @Success 200 {string} json "{"code" : 200, data: {}, "msg" : "ok"}" +// @Router /v1/users [post] +func AddUser(c *gin.Context) { + username := c.PostForm("username") + password := c.PostForm("password") + nickname := c.PostForm("nickname") + + valid := validation.Validation{} + valid.Required(username, "username").Message("用户名不能为空") + valid.Required(password, "password").Message("密码不能为空") + valid.Required(nickname, "password").Message("真实姓名不能为空") + + data := make(map[string]interface{}) + code := e.INVALID_PARAMS + + if ! valid.HasErrors() { + if ! models.ExistUserByUsername(username) { + data["Username"] = username + data["Password"] = models.GetSecretPassword(password) + data["Nickname"] = nickname + code = e.SUCCESS + } else { + code = e.ERROR_EXIST_USER + } + } + + if code == 200 { + models.AddUser(data) + } + + c.JSON(http.StatusOK, gin.H{ + "code" : code, + "msg" : e.GetMsg(code), + "data" : data, + }) +} \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index b90c6da..e0cb0b2 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-08-12 01:35:45.643682 +0800 CST m=+0.068783392 +// 2019-08-12 20:14:10.089932 +0800 CST m=+0.057625886 package docs @@ -26,6 +26,41 @@ var doc = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/v1/auth": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "用户验证", + "parameters": [ + { + "type": "string", + "description": "用户 用户名", + "name": "username", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "用户 密码", + "name": "password", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\" : 200, \"data\" : {\"token\" : \"\"}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + } + }, "/v1/businesses": { "get": { "consumes": [ @@ -38,6 +73,15 @@ var doc = `{ "businesses" ], "summary": "业务系统列表", + "parameters": [ + { + "type": "string", + "description": "auth by /auth", + "name": "Authorization", + "in": "header", + "required": true + } + ], "responses": { "200": { "description": "{\"code\" : 200, \"data\" : {}, \"msg\" : \"ok\"}", @@ -418,6 +462,71 @@ var doc = `{ } } }, + "/v1/users": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "用户列表", + "responses": { + "200": { + "description": "{\"code\" : 200, \"data\" : {}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "新增用户", + "parameters": [ + { + "type": "string", + "description": "用户 用户名", + "name": "username", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "用户 密码", + "name": "password", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "用户 真实姓名", + "name": "nickname", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\" : 200, data: {}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + } + }, "/v1/vendors": { "get": { "consumes": [ diff --git a/docs/swagger.json b/docs/swagger.json index 0c310fb..a665297 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -9,6 +9,41 @@ }, "basePath": "/api", "paths": { + "/v1/auth": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "用户验证", + "parameters": [ + { + "type": "string", + "description": "用户 用户名", + "name": "username", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "用户 密码", + "name": "password", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\" : 200, \"data\" : {\"token\" : \"\"}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + } + }, "/v1/businesses": { "get": { "consumes": [ @@ -21,6 +56,15 @@ "businesses" ], "summary": "业务系统列表", + "parameters": [ + { + "type": "string", + "description": "auth by /auth", + "name": "Authorization", + "in": "header", + "required": true + } + ], "responses": { "200": { "description": "{\"code\" : 200, \"data\" : {}, \"msg\" : \"ok\"}", @@ -401,6 +445,71 @@ } } }, + "/v1/users": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "用户列表", + "responses": { + "200": { + "description": "{\"code\" : 200, \"data\" : {}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + }, + "post": { + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "新增用户", + "parameters": [ + { + "type": "string", + "description": "用户 用户名", + "name": "username", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "用户 密码", + "name": "password", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "用户 真实姓名", + "name": "nickname", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"code\" : 200, data: {}, \"msg\" : \"ok\"}", + "schema": { + "type": "string" + } + } + } + } + }, "/v1/vendors": { "get": { "consumes": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 5e4a82d..9ffc84b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -6,10 +6,39 @@ info: title: Potato Api version: "1.0" paths: + /v1/auth: + get: + consumes: + - application/json + parameters: + - description: 用户 用户名 + in: query + name: username + required: true + type: string + - description: 用户 密码 + in: query + name: password + required: true + type: string + produces: + - application/json + responses: + "200": + description: '{"code" : 200, "data" : {"token" : ""}, "msg" : "ok"}' + schema: + type: string + summary: 用户验证 /v1/businesses: get: consumes: - application/json + parameters: + - description: auth by /auth + in: header + name: Authorization + required: true + type: string produces: - application/json responses: @@ -265,6 +294,49 @@ paths: summary: 元数据列表 tags: - meta_tables + /v1/users: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: '{"code" : 200, "data" : {}, "msg" : "ok"}' + schema: + type: string + summary: 用户列表 + tags: + - users + post: + consumes: + - multipart/form-data + parameters: + - description: 用户 用户名 + in: formData + name: username + required: true + type: string + - description: 用户 密码 + in: formData + name: password + required: true + type: string + - description: 用户 真实姓名 + in: formData + name: nickname + required: true + type: string + produces: + - application/json + responses: + "200": + description: '{"code" : 200, data: {}, "msg" : "ok"}' + schema: + type: string + summary: 新增用户 + tags: + - users /v1/vendors: get: consumes: diff --git a/middleware/jwt/jwt.go b/middleware/jwt/jwt.go index 0eeac6a..39417fc 100644 --- a/middleware/jwt/jwt.go +++ b/middleware/jwt/jwt.go @@ -1,9 +1,9 @@ package jwt import ( - "game_demo/pkg/e" - "game_demo/pkg/util" "github.com/gin-gonic/gin" + "github.com/viletyy/potato/pkg/e" + "github.com/viletyy/potato/pkg/util" "net/http" "time" ) @@ -24,13 +24,19 @@ func JWT() gin.HandlerFunc { } else if time.Now().Unix() > claims.ExpiresAt { code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT } + username := claims.Username + loginUUID := claims.StandardClaims.Id + val, err := util.Redis.Get("login:" + loginUUID).Result() + if val != username { + code = e.ERROR_AUTH_CHECK_TOKEN_FAIL + } } if code != e.SUCCESS { c.JSON(http.StatusUnauthorized, gin.H{ "code" : code, "msg" : e.GetMsg(code), - "basic" : data, + "data" : data, }) c.Abort() diff --git a/models/basic/migrate.go b/models/basic/migrate.go deleted file mode 100644 index 5635aab..0000000 --- a/models/basic/migrate.go +++ /dev/null @@ -1,7 +0,0 @@ -package basic - -import "github.com/viletyy/potato/pkg/util" - -func init() { - util.DB.AutoMigrate(&MetaDatabase{}, &Vendor{}, &Business{}) -} \ No newline at end of file diff --git a/models/migrate.go b/models/migrate.go new file mode 100644 index 0000000..68f4e40 --- /dev/null +++ b/models/migrate.go @@ -0,0 +1,10 @@ +package models + +import ( + "github.com/viletyy/potato/models/basic" + "github.com/viletyy/potato/pkg/util" +) + +func init() { + util.DB.AutoMigrate(&User{}, &basic.MetaDatabase{}, &basic.Vendor{}, &basic.Business{}) +} \ No newline at end of file diff --git a/models/user.go b/models/user.go new file mode 100644 index 0000000..821abb8 --- /dev/null +++ b/models/user.go @@ -0,0 +1,84 @@ +package models + +import ( + "crypto/md5" + "fmt" + "github.com/viletyy/potato/pkg/util" + "io" + "log" +) + +type User struct { + util.Model + + Username string `json:"username"` + Password string `json:"password"` + Nickname string `json:"nickname"` +} + +func CheckUser(username, password string) bool { + var user User + util.DB.Select("id").Where(User{Username: username, Password: GetSecretPassword(password)}).First(&user) + if user.ID > 0 { + return true + } + return false +} + +func GetSecretPassword(password string) string { + h := md5.New() + io.WriteString(h, password) + final := fmt.Sprintf("%x", h.Sum(nil)) + return final +} + +func GetUsers(pageNum int, pageSize int, maps interface{}) (users []User) { + util.DB.Where(maps).Offset(pageNum).Limit(pageSize).Find(&users) + return +} + +func GetUsersTotal(maps interface{}) (count int) { + util.DB.Model(&User{}).Where(maps).Count(&count) + return +} + +func ExistUserByUsername(username string) bool { + var user User + util.DB.Select("id").Where("name = ?", username).First(&user) + if user.ID > 0 { + return true + } + return false +} + +func ExistUserById(id int) bool { + var user User + util.DB.Select("id").Where("id = ?", id).First(&user) + if user.ID > 0 { + return true + } + return false +} + +func AddUser(data map[string]interface{}) bool { + user := &User{} + error := util.FillStruct(data, user) + if error != nil { + log.Printf("Fill Struct is Fail") + } + util.DB.Create(user) + + return true +} + +func EditUser(id int, data interface{}) bool { + util.DB.Model(&User{}).Where("id = ?", id).Update(data) + + return true +} + +func DeleteUser(id int) bool { + util.DB.Where("id = ?", id).Delete(&User{}) + + return true +} \ No newline at end of file diff --git a/pkg/e/code.go b/pkg/e/code.go index 12ea392..c34fbfb 100644 --- a/pkg/e/code.go +++ b/pkg/e/code.go @@ -5,6 +5,8 @@ const ( ERROR = 500 INVALID_PARAMS = 400 + ERROR_EXIST_USER = 10001 + ERROR_NOT_EXIST_USER = 10002 ERROR_EXIST_VENDOR = 10011 ERROR_NOT_EXIST_VENDOR = 10012 ERROR_EXIST_BUSINESS = 10021 diff --git a/pkg/e/msg.go b/pkg/e/msg.go index 8f69568..cc80fbb 100644 --- a/pkg/e/msg.go +++ b/pkg/e/msg.go @@ -4,6 +4,9 @@ var MsgFlags = map[int]string { SUCCESS : "ok", ERROR : "fail", INVALID_PARAMS : "请求参数错误", + + ERROR_EXIST_USER : "已存在该用户", + ERROR_NOT_EXIST_USER : "该用户不存在", ERROR_EXIST_VENDOR : "已存在该系统厂商", ERROR_NOT_EXIST_VENDOR : "该系统厂商不存在", ERROR_EXIST_BUSINESS : "已存在该业务系统", diff --git a/pkg/util/Instance.go b/pkg/util/Instance.go index dcfaaaa..df4a24c 100644 --- a/pkg/util/Instance.go +++ b/pkg/util/Instance.go @@ -32,7 +32,7 @@ func init() { InitDB() //defer DB.Close() InitRedis() - defer Redis.Close() + //defer Redis.Close() } func InitDB() *gorm.DB { @@ -75,7 +75,7 @@ func InitDB() *gorm.DB { return DB } -func InitRedis() { +func InitRedis() *redis.Client { sec, err := setting.Cfg.GetSection("redis") if err != nil { @@ -89,9 +89,11 @@ func InitRedis() { ), }) - if _, err := Redis.Ping().Result(); err != nil { + _, err = Redis.Ping().Result() + if err != nil { logging.Fatal("redis连接失败!", err) } + return Redis } func FillStruct(data map[string]interface{}, obj interface{}) error { diff --git a/pkg/util/jwt.go b/pkg/util/jwt.go index 25a6536..8f1c992 100644 --- a/pkg/util/jwt.go +++ b/pkg/util/jwt.go @@ -1,7 +1,9 @@ package util import ( + "fmt" "github.com/dgrijalva/jwt-go" + "github.com/google/uuid" "github.com/viletyy/potato/pkg/setting" "time" ) @@ -16,19 +18,23 @@ type Claims struct { func GenerateToken(username, password string) (string, error) { nowTime := time.Now() - expireTime := nowTime.Add(3 * time.Hour) + expireTime := nowTime.Add(time.Minute * 30) + loginUUID := uuid.New().String() claims := Claims{ Username: username, Password: password, StandardClaims: jwt.StandardClaims{ ExpiresAt: expireTime.Unix(), - Issuer : "gin-game-demo", + Issuer : "data_govern", + Id : loginUUID, }, } tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token, err := tokenClaims.SignedString(jwtSecret) + result, err := Redis.Set("login:" + loginUUID, username, 1*time.Hour).Result() + fmt.Println(result, err) return token, err } diff --git a/routers/router.go b/routers/router.go index cab5ac0..43fe5ea 100644 --- a/routers/router.go +++ b/routers/router.go @@ -6,9 +6,10 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" _ "github.com/swaggo/gin-swagger/swaggerFiles" - "github.com/viletyy/potato/controller/api" + v1 "github.com/viletyy/potato/controller/api/v1" _ "github.com/viletyy/potato/docs" "github.com/viletyy/potato/middleware/cors" + "github.com/viletyy/potato/middleware/jwt" "github.com/viletyy/potato/pkg/setting" ) @@ -26,7 +27,7 @@ func InitRouter() *gin.Engine { Engine.Use(cors.CORSMiddleware()) - Engine.GET("/auth", api.GetAuth) + Engine.GET("/api/v1/auth", v1.GetUserAuth) Engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) V1InitModule() @@ -35,5 +36,9 @@ func InitRouter() *gin.Engine { } func V1InitModule() { + V1RouterGroup.Use(jwt.JWT()) + users := V1RouterGroup.Group("users") + users.GET("", v1.GetUsers) + users.POST("", v1.AddUser) V1InitBasicRouter() }