├── config.json ├── .idea ├── misc.xml ├── vcs.xml ├── modules.xml ├── lib-demo.iml └── workspace.xml ├── datasource ├── tableInit.go └── datasource.go ├── utils ├── deferutil.go ├── jsonutil.go ├── hmacsha256util.go └── md5.go ├── models ├── book.go ├── result.go └── user.go ├── conf └── sysconfig.go ├── README.md ├── main.go ├── route └── route.go ├── controllers ├── user_controller.go └── book_controller.go ├── repo ├── book_repo.go └── user_repo.go ├── service ├── user_service.go └── book_service.go ├── middleware └── jwt.go └── db ├── test.sql └── iris-gorm-demo.postman_collection.json /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Port": "8848", 3 | "DBUserName": "root", 4 | "DBPassword": "123456", 5 | "DBIp": "127.0.0.1", 6 | "DBPort": "3306", 7 | "DBName": "test" 8 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /datasource/tableInit.go: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "../models" 5 | ) 6 | // 初始化表 如果不存在该表 则自动创建 7 | func Createtable() { 8 | GetDB().AutoMigrate( 9 | &models.User{}, 10 | &models.Book{}, 11 | ) 12 | } -------------------------------------------------------------------------------- /utils/deferutil.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | ) 6 | 7 | func Defer(tx *gorm.DB, code *int) { 8 | if *code == 0{ 9 | //提交事务 10 | tx.Commit() 11 | } else { 12 | //回滚 13 | tx.Rollback() 14 | } 15 | } -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/lib-demo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /utils/jsonutil.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/json" 4 | 5 | //interface{}可以储存任意类型的数值 6 | func JsonEncode(code int, data interface{}, msg string) ([]byte, error) { 7 | result := struct { 8 | Code int 9 | Data interface{} 10 | Msg string 11 | }{code, data, msg} 12 | return json.Marshal(result) 13 | } 14 | -------------------------------------------------------------------------------- /models/book.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | ) 6 | 7 | type Book struct { 8 | gorm.Model 9 | Name string `gorm:"type:varchar(20);not null;"` 10 | Count string `gorm:"type:varchar(10);not null;"` 11 | Author string `gorm:"type:varchar(20);not null;"` 12 | Type string `gorm:"type:varchar(20);not null;"` 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /utils/hmacsha256util.go: -------------------------------------------------------------------------------- 1 | 2 | package utils 3 | 4 | import ( 5 | "crypto/hmac" 6 | "crypto/sha256" 7 | "encoding/base64" 8 | "encoding/hex" 9 | ) 10 | 11 | func HmacSha256Encode(strings string, secret string) string { 12 | key := []byte(secret) 13 | h := hmac.New(sha256.New, key) 14 | h.Write([]byte(strings)) 15 | sha := hex.EncodeToString(h.Sum(nil)) 16 | 17 | return base64.StdEncoding.EncodeToString([]byte(sha)) 18 | } 19 | -------------------------------------------------------------------------------- /models/result.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Result struct { 4 | Code int 5 | Msg string 6 | Data interface{} 7 | } 8 | 9 | func NewResult(data interface{}, c int, m ...string) *Result { 10 | r := &Result{Data: data, Code: c} 11 | 12 | if e, ok := data.(error); ok { 13 | if m == nil { 14 | r.Msg = e.Error() 15 | } 16 | } else { 17 | r.Msg = "SUCCESS" 18 | } 19 | if len(m) > 0 { 20 | r.Msg = m[0] 21 | } 22 | 23 | return r 24 | } 25 | -------------------------------------------------------------------------------- /models/user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "github.com/jinzhu/gorm" 4 | 5 | type User struct { 6 | gorm.Model 7 | Username string `gorm:"unique"` 8 | Password string 9 | Name string //姓名 10 | Email string //邮箱 11 | Mobile string //手机 12 | QQ string 13 | Gender int //0男 1女 14 | Age int //年龄 15 | Remark string //备注 16 | Token string `gorm:"-"` 17 | Session string `gorm:"-"` 18 | } 19 | -------------------------------------------------------------------------------- /conf/sysconfig.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/json-iterator/go" 5 | "io/ioutil" 6 | ) 7 | 8 | var Sysconfig = &sysconfig{} 9 | 10 | func init() { 11 | //指定对应的json配置文件 12 | b, err := ioutil.ReadFile("config.json") 13 | if err != nil { 14 | panic("Sys config read err") 15 | } 16 | err = jsoniter.Unmarshal(b, Sysconfig) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | } 22 | 23 | type sysconfig struct { 24 | Port string `json:"Port"` 25 | DBUserName string `json:"DBUserName"` 26 | DBPassword string `json:"DBPassword"` 27 | DBIp string `json:"DBIp"` 28 | DBPort string `json:"DBPort"` 29 | DBName string `json:"DBName"` 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iris-gorm-demo 2 | 与lib-ui对应的服务端代码,使用iris+gorm+mysql搭建的一个restful项目模板 3 | 4 | #### 12.26更新 5 | 1. 优化代码结构 6 | 2. jwt实现 7 | 3. json传参 8 | 4. md5处理 9 | ``` 10 | conf 配置文件 11 | controllers 控制器 入参处理 api的入口 12 | datasource 数据库配置 13 | models 结构体 14 | db sql数据文件 postman接口文件 15 | repo 数据库的操作 16 | middleware 中间件 jwt实现 17 | route 注册路由 18 | service 业务逻辑代码 19 | utils 工具类 20 | config.json 配置文件的映射 21 | main.go 主程序入口 22 | ``` 23 | ### 启动项目 24 | ``` 25 | 1.安装依赖 go get 26 | 2.go run main.go 27 | ``` 28 | 1. 使用go get直接下载依赖,或在github手动下载包放到gopath/src/github.com/ 29 | 2. 导包时使用相对路径需要将项目放在你配置的GOPATH目录下 30 | 3. 这里我没有使用go module来管理依赖,是因为下载包很容易被墙。你可以使用go mod init用go mod来管理 31 | 32 | #### 前端 33 | https://github.com/pppercyWang/lib-ui 34 | -------------------------------------------------------------------------------- /utils/md5.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/rand" 6 | "encoding/base64" 7 | "encoding/hex" 8 | "io" 9 | ) 10 | 11 | func GetMD5String(strings string) string { 12 | 13 | md5Ctx := md5.New() 14 | md5Ctx.Write([]byte(strings)) 15 | cipherStr := md5Ctx.Sum(nil) 16 | return hex.EncodeToString(cipherStr) 17 | } 18 | func Md5ByByte(bytes []byte) string { 19 | 20 | md5Ctx := md5.New() 21 | md5Ctx.Write(bytes) 22 | cipherStr := md5Ctx.Sum(nil) 23 | return hex.EncodeToString(cipherStr) 24 | } 25 | 26 | //生成Guid字串 27 | func UniqueId() string { 28 | b := make([]byte, 48) 29 | if _, err := io.ReadFull(rand.Reader, b); err != nil { 30 | return "" 31 | } 32 | return GetMD5String(base64.URLEncoding.EncodeToString(b)) 33 | } 34 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./conf" 5 | "./route" 6 | "flag" 7 | "github.com/iris-contrib/middleware/cors" 8 | "github.com/kataras/iris" 9 | ) 10 | 11 | func main() { 12 | flag.Parse() 13 | app := newApp() 14 | route.InitRouter(app) 15 | err := app.Run(iris.Addr(":"+conf.Sysconfig.Port), iris.WithoutServerError(iris.ErrServerClosed)) 16 | if err != nil { 17 | panic(err) 18 | } 19 | } 20 | 21 | func newApp() *iris.Application { 22 | app := iris.New() 23 | app.Configure(iris.WithOptimizations) 24 | crs := cors.New(cors.Options{ 25 | AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts. 26 | AllowCredentials: true, 27 | AllowedHeaders: []string{"*"}, 28 | }) 29 | app.Use(crs) 30 | app.AllowMethods(iris.MethodOptions) 31 | return app 32 | } 33 | -------------------------------------------------------------------------------- /route/route.go: -------------------------------------------------------------------------------- 1 | package route 2 | 3 | import ( 4 | "../controllers" 5 | "github.com/kataras/iris" 6 | "github.com/kataras/iris/mvc" 7 | "net/http" 8 | "../middleware" 9 | ) 10 | 11 | func InitRouter(app *iris.Application) { 12 | //app.Use(CrossAccess) 13 | bathUrl := "/api" 14 | mvc.New(app.Party(bathUrl + "/user")).Handle(controllers.NewUserController()) 15 | app.Use(middleware.GetJWT().Serve) // jwt 16 | mvc.New(app.Party(bathUrl +"/book")).Handle(controllers.NewBookController()) 17 | } 18 | 19 | func CrossAccess11(next http.Handler) http.Handler { 20 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 21 | w.Header().Add("Access-Control-Allow-Origin", "*") 22 | next.ServeHTTP(w, r) 23 | }) 24 | } 25 | func CrossAccess(ctx iris.Context) { 26 | ctx.ResponseWriter().Header().Add("Access-Control-Allow-Origin", "*") 27 | } 28 | -------------------------------------------------------------------------------- /datasource/datasource.go: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "../conf" 5 | _ "github.com/go-sql-driver/mysql" 6 | "github.com/jinzhu/gorm" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | var db *gorm.DB 12 | 13 | func GetDB() *gorm.DB { 14 | return db 15 | } 16 | 17 | func init() { 18 | path := strings.Join([]string{conf.Sysconfig.DBUserName, ":", conf.Sysconfig.DBPassword, "@(", conf.Sysconfig.DBIp, ":", conf.Sysconfig.DBPort, ")/", conf.Sysconfig.DBName, "?charset=utf8&parseTime=true"}, "") 19 | var err error 20 | db, err = gorm.Open("mysql", path) 21 | if err !=nil{ 22 | panic(err) 23 | } 24 | db.SingularTable(true) 25 | db.DB().SetConnMaxLifetime(1 * time.Second) 26 | db.DB().SetMaxIdleConns(20) //最大打开的连接数 27 | db.DB().SetMaxOpenConns(2000) //设置最大闲置个数 28 | db.SingularTable(true) //表生成结尾不带s 29 | // 启用Logger,显示详细日志 30 | db.LogMode(true) 31 | Createtable(); 32 | } 33 | -------------------------------------------------------------------------------- /controllers/user_controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "../models" 5 | "../service" 6 | "github.com/kataras/iris" 7 | "log" 8 | ) 9 | 10 | type UserController struct { 11 | Ctx iris.Context 12 | Service service.UserService 13 | } 14 | 15 | func NewUserController() *UserController { 16 | return &UserController{Service: service.NewUserServices()} 17 | } 18 | 19 | 20 | func (g *UserController) PostLogin() models.Result { 21 | var m map[string]string 22 | err := g.Ctx.ReadJSON(&m) 23 | if err != nil { 24 | log.Println("ReadJSON Error:", err) 25 | } 26 | result := g.Service.Login(m) 27 | return result 28 | } 29 | 30 | func (g *UserController) PostSave() (result models.Result) { 31 | var user models.User 32 | if err := g.Ctx.ReadJSON(&user); err != nil { 33 | log.Println(err) 34 | result.Msg = "数据错误" 35 | return 36 | } 37 | 38 | return g.Service.Save(user) 39 | } 40 | 41 | -------------------------------------------------------------------------------- /repo/book_repo.go: -------------------------------------------------------------------------------- 1 | package repo 2 | 3 | import ( 4 | "../datasource" 5 | "../models" 6 | "github.com/spf13/cast" 7 | ) 8 | type BookRepository interface { 9 | GetBookList(m map[string]interface{})(total int,books []models.Book) 10 | SaveBook(book models.Book)(err error) 11 | GetBook(id uint)(book models.Book,err error) 12 | DelBook(id uint)(err error) 13 | } 14 | func NewBookRepository() BookRepository{ 15 | return &bookRepository{} 16 | } 17 | var db = datasource.GetDB() 18 | 19 | type bookRepository struct {} 20 | 21 | func (n bookRepository) GetBookList(m map[string]interface{})(total int,books []models.Book){ 22 | db.Table("book").Count(&total) 23 | err := db.Limit(cast.ToInt(m["size"])).Offset((cast.ToInt(m["page"])-1)*cast.ToInt(m["size"])).Find(&books).Error 24 | if err!=nil { 25 | panic("select Error") 26 | } 27 | return 28 | } 29 | func (n bookRepository) SaveBook(book models.Book)(err error){ 30 | if book.ID != 0{ 31 | err := db.Save(&book).Error 32 | return err 33 | }else { 34 | err := db.Create(&book).Error 35 | return err 36 | } 37 | } 38 | func (n bookRepository) GetBook(id uint)(book models.Book,err error){ 39 | err = db.First(&book,id).Error 40 | return 41 | } 42 | func (n bookRepository) DelBook(id uint)(err error){ 43 | var book models.Book 44 | book.ID = id 45 | err = db.Unscoped().Delete(&book).Error //如果直接Delete是软删除 46 | return 47 | } 48 | 49 | -------------------------------------------------------------------------------- /service/user_service.go: -------------------------------------------------------------------------------- 1 | 2 | package service 3 | 4 | import ( 5 | "../models" 6 | "../repo" 7 | "../utils" 8 | "../middleware" 9 | // "fmt" 10 | // "github.com/spf13/cast" 11 | // "log" 12 | ) 13 | 14 | type UserService interface { 15 | Login(m map[string]string) (result models.Result) 16 | Save(user models.User) (result models.Result) 17 | } 18 | type userServices struct { 19 | 20 | } 21 | 22 | func NewUserServices() UserService { 23 | return &userServices{} 24 | } 25 | 26 | var userRepo = repo.NewUserRepository() 27 | 28 | /* 29 | 登录 30 | */ 31 | func (u userServices) Login(m map[string]string) (result models.Result) { 32 | 33 | if m["username"] == "" { 34 | result.Code = -1 35 | result.Msg = "请输入用户名!" 36 | return 37 | } 38 | if m["password"] == "" { 39 | result.Code = -1 40 | result.Msg = "请输入密码!" 41 | return 42 | } 43 | user := userRepo.GetUserByUserNameAndPwd(m["username"],utils.GetMD5String(m["password"])) 44 | if user.ID == 0 { 45 | result.Code = -1 46 | result.Msg = "用户名或密码错误!" 47 | return 48 | } 49 | user.Token = middleware.GenerateToken(user) 50 | result.Code = 0 51 | result.Data = user 52 | result.Msg = "登录成功" 53 | return 54 | } 55 | 56 | /* 57 | 保存 58 | */ 59 | func (u userServices) Save(user models.User) (result models.Result){ 60 | //添加 61 | if user.ID == 0 { 62 | agen := userRepo.GetUserByUsername(user.Username) 63 | if agen.ID != 0 { 64 | result.Msg = "登录名重复,保存失败" 65 | return 66 | } 67 | } 68 | code,p := userRepo.Save(user) 69 | if code == -1 { 70 | result.Code = -1; 71 | result.Msg = "保存失败" 72 | return 73 | } 74 | result.Code = 0 75 | result.Data = p 76 | return 77 | } 78 | 79 | -------------------------------------------------------------------------------- /service/book_service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "../models" 5 | "../repo" 6 | ) 7 | type BookService interface { 8 | GetBookList (m map[string]interface{}) (result models.Result) 9 | SaveBook(book models.Book) (result models.Result) 10 | GetBook(id uint) (result models.Result) 11 | DelBook(id uint) (result models.Result) 12 | } 13 | 14 | type bookService struct {} 15 | 16 | func NewBookService() BookService{ 17 | return &bookService{} 18 | } 19 | 20 | var bookRepo = repo.NewBookRepository() 21 | 22 | func (u bookService)GetBookList (m map[string]interface{}) (result models.Result){ 23 | total,books := bookRepo.GetBookList(m) 24 | maps := make(map[string]interface{},2) 25 | maps["Total"] = total 26 | maps["List"] = books 27 | result.Data = maps 28 | result.Code = 0 29 | result.Msg ="SUCCESS" 30 | return 31 | } 32 | func (n bookService) SaveBook(book models.Book)(result models.Result){ 33 | err := bookRepo.SaveBook(book) 34 | if err != nil{ 35 | result.Code = -1 36 | result.Msg ="保存失败" 37 | }else{ 38 | result.Code = 1 39 | result.Msg ="保存成功" 40 | } 41 | return 42 | } 43 | func (n bookService) GetBook(id uint)(result models.Result){ 44 | book,err := bookRepo.GetBook(id) 45 | if err!= nil{ 46 | result.Code = -1 47 | result.Msg = err.Error() 48 | }else{ 49 | result.Data = book 50 | result.Code = 0 51 | result.Msg ="SUCCESS" 52 | } 53 | return 54 | } 55 | func (n bookService) DelBook(id uint)(result models.Result){ 56 | err := bookRepo.DelBook(id) 57 | if err!= nil{ 58 | result.Code = -1 59 | result.Msg = err.Error() 60 | }else{ 61 | result.Code = 0 62 | result.Msg ="SUCCESS" 63 | } 64 | return 65 | } 66 | 67 | -------------------------------------------------------------------------------- /repo/user_repo.go: -------------------------------------------------------------------------------- 1 | 2 | package repo 3 | 4 | import ( 5 | "../datasource" 6 | "../models" 7 | "../utils" 8 | // "github.com/spf13/cast" 9 | "log" 10 | ) 11 | 12 | type UserRepository interface { 13 | GetUserByUserNameAndPwd(username string, password string) (user models.User) 14 | GetUserByUsername(username string) (user models.User) 15 | Save(user models.User) (int, models.User) 16 | } 17 | 18 | func NewUserRepository() UserRepository { 19 | return &userRepository{} 20 | } 21 | 22 | type userRepository struct{} 23 | 24 | //登录 25 | func (n userRepository) GetUserByUserNameAndPwd(username string, password string) (user models.User) { 26 | db := datasource.GetDB() 27 | db.Where("username = ? and password = ?", username, password).First(&user) 28 | return 29 | } 30 | func (n userRepository) GetUserByUsername(username string) (user models.User) { 31 | db := datasource.GetDB() 32 | db.Where("username = ?", username).First(&user) 33 | return 34 | } 35 | 36 | //添加/修改 37 | func (n userRepository) Save(user models.User) (int, models.User) { 38 | code := 0 39 | tx := datasource.GetDB().Begin() 40 | defer utils.Defer(tx,&code) 41 | if user.ID != 0 { 42 | var oldUser models.User 43 | datasource.GetDB().First(&oldUser, user.ID) 44 | user.CreatedAt = oldUser.CreatedAt 45 | user.Username = oldUser.Username 46 | if user.Name == "" { 47 | user.Name = oldUser.Name 48 | } 49 | if user.Email == "" { 50 | user.Email = oldUser.Email 51 | } 52 | if user.Mobile == "" { 53 | user.Mobile = oldUser.Mobile 54 | } 55 | if user.QQ == "" { 56 | user.QQ = oldUser.QQ 57 | } 58 | if user.Gender == 0 { 59 | user.Gender = oldUser.Gender 60 | } 61 | if user.Age == 0 { 62 | user.Age = oldUser.Age 63 | } 64 | if user.Remark == "" { 65 | user.Remark = oldUser.Remark 66 | } 67 | } 68 | if user.Password != "" { 69 | user.Password = utils.GetMD5String(user.Password) 70 | } 71 | if err := tx.Save(&user).Error; err != nil { 72 | log.Println(err) 73 | code = -1 74 | } 75 | return code, user 76 | } 77 | -------------------------------------------------------------------------------- /controllers/book_controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "../models" 5 | "../service" 6 | "log" 7 | "github.com/kataras/iris" 8 | "github.com/spf13/cast" 9 | ) 10 | 11 | type BookController struct { 12 | Ctx iris.Context 13 | Service service.BookService 14 | } 15 | func NewBookController() *BookController { 16 | return &BookController{Service:service.NewBookService()} 17 | } 18 | func (g *BookController) PostList()(result models.Result) { 19 | var m map[string]interface{} 20 | err := g.Ctx.ReadJSON(&m) 21 | if err != nil { 22 | log.Println("ReadJSON Error:", err) 23 | } 24 | if m["page"] == "" || m["page"] == nil { 25 | result.Code = -1 26 | result.Msg = "参数缺失 page" 27 | return 28 | } 29 | if cast.ToUint(m["page"]) == 0 { 30 | result.Code = -1 31 | result.Msg = "参数错误 page" 32 | return 33 | } 34 | if m["size"] == "" || m["size"] == nil { 35 | result.Code = -1 36 | result.Msg = "参数缺失 size" 37 | return 38 | } 39 | if cast.ToUint(m["size"]) == 0 { 40 | result.Code = -1 41 | result.Msg = "参数错误 size" 42 | return 43 | } 44 | return g.Service.GetBookList(m) 45 | } 46 | func (g *BookController) PostSave()(result models.Result) { 47 | var book models.Book 48 | if err := g.Ctx.ReadJSON(&book); err != nil { 49 | log.Println(err) 50 | result.Msg = "数据错误" 51 | return 52 | } 53 | return g.Service.SaveBook(book) 54 | } 55 | func (g *BookController) PostGet()(result models.Result) { 56 | var m map[string]interface{} 57 | err := g.Ctx.ReadJSON(&m) 58 | if err != nil { 59 | log.Println("ReadJSON Error:", err) 60 | } 61 | if m["id"] == "" || m["id"] == nil { 62 | result.Code = -1 63 | result.Msg = "参数缺失 id" 64 | return 65 | } 66 | if cast.ToUint(m["id"]) == 0 { 67 | result.Code = -1 68 | result.Msg = "参数错误 id" 69 | return 70 | } 71 | return g.Service.GetBook(cast.ToUint(m["id"])) 72 | } 73 | func (g *BookController) PostDel()(result models.Result) { 74 | var m map[string]interface{} 75 | err := g.Ctx.ReadJSON(&m) 76 | if err != nil { 77 | log.Println("ReadJSON Error:", err) 78 | } 79 | if m["id"] == "" || m["id"] == nil { 80 | result.Code = -1 81 | result.Msg = "参数缺失 id" 82 | return 83 | } 84 | if cast.ToUint(m["id"]) == 0 { 85 | result.Code = -1 86 | result.Msg = "参数错误 id" 87 | return 88 | } 89 | return g.Service.DelBook(cast.ToUint(m["id"])) 90 | } -------------------------------------------------------------------------------- /middleware/jwt.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "../models" 5 | "fmt" 6 | "github.com/dgrijalva/jwt-go" 7 | jwtmiddleware "github.com/iris-contrib/middleware/jwt" 8 | "github.com/kataras/iris" 9 | "github.com/spf13/cast" 10 | "log" 11 | "time" 12 | ) 13 | 14 | const JwtKey = "percy" 15 | 16 | func GetJWT() *jwtmiddleware.Middleware { 17 | jwtHandler := jwtmiddleware.New(jwtmiddleware.Config{ 18 | //这个方法将验证jwt的token 19 | ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { 20 | //自己加密的秘钥或者说盐值 21 | return []byte(JwtKey), nil 22 | }, 23 | //加密的方式 24 | SigningMethod: jwt.SigningMethodHS256, 25 | //验证未通过错误处理方式 26 | ErrorHandler: func(ctx iris.Context, s string) { 27 | 28 | fmt.Println("错误:", s) 29 | result := models.Result{Code: -1, Msg: "认证失败,请重新登录认证"} 30 | i, err := ctx.JSON(result) 31 | if err != nil { 32 | log.Println(i, err) 33 | } 34 | }, 35 | }) 36 | return jwtHandler 37 | } 38 | 39 | //生成token 40 | func GenerateToken(user models.User) string { 41 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ 42 | "nick_name": user.Username, //用户信息 43 | "session": user.Session, //session 44 | "id": user.ID, //用户信息 45 | "iss": "Iris", //签发者 46 | "iat": time.Now().Unix(), //签发时间 47 | "jti": "9527", //jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 48 | "exp": time.Now().Add(10 * time.Hour * time.Duration(1)).Unix(), //过期时间 49 | }) 50 | tokenString, _ := token.SignedString([]byte(JwtKey)) 51 | fmt.Println("签发时间:", time.Now().Unix()) 52 | fmt.Println("到期时间:", time.Now().Add(10 * time.Hour * time.Duration(1)).Unix()) 53 | return tokenString 54 | } 55 | 56 | func ParseToken(tokenString string, key string) (interface{}, bool) { 57 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { 58 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 59 | return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) 60 | } 61 | return []byte(key), nil 62 | }) 63 | if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { 64 | return claims, true 65 | } else { 66 | fmt.Println(err) 67 | return "", false 68 | } 69 | } 70 | 71 | func GetToken(ctx iris.Context) string { 72 | token := ctx.GetHeader("Authorization") 73 | if token != "" && len(token) > 7 { 74 | token = token[7:] 75 | } 76 | return token 77 | } 78 | func GetUserID(token string) int { 79 | var userId = 0 80 | if token != "" && token != "undefined" && len(token) > 7 { 81 | v, _ := ParseToken(token, JwtKey) 82 | if v != "" { 83 | userId = cast.ToInt(v.(jwt.MapClaims)["id"]) 84 | } 85 | } 86 | return userId 87 | } 88 | -------------------------------------------------------------------------------- /db/test.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Type : MySQL 6 | Source Server Version : 50716 7 | Source Host : localhost:3306 8 | Source Schema : test 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50716 12 | File Encoding : 65001 13 | 14 | Date: 26/12/2019 11:34:45 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for book 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `book`; 24 | CREATE TABLE `book` ( 25 | `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, 26 | `created_at` timestamp(0) NULL DEFAULT NULL, 27 | `updated_at` timestamp(0) NULL DEFAULT NULL, 28 | `deleted_at` timestamp(0) NULL DEFAULT NULL, 29 | `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 30 | `count` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 31 | `author` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 32 | `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 33 | PRIMARY KEY (`id`) USING BTREE, 34 | INDEX `idx_book_deleted_at`(`deleted_at`) USING BTREE 35 | ) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 36 | 37 | -- ---------------------------- 38 | -- Records of book 39 | -- ---------------------------- 40 | INSERT INTO `book` VALUES (2, '2019-12-26 02:16:44', '2019-12-26 02:16:44', NULL, '红楼梦', '20', '曹雪芹', '言情'); 41 | INSERT INTO `book` VALUES (3, '2019-12-26 02:18:45', '2019-12-26 02:18:45', NULL, '西游记', '12', '吴承恩', '玄幻'); 42 | INSERT INTO `book` VALUES (9, '2019-12-26 02:50:40', '2019-12-26 02:50:40', NULL, '三国演义', '19', '罗贯中', '历史'); 43 | INSERT INTO `book` VALUES (10, '2019-12-26 02:50:41', '2019-12-26 02:50:41', NULL, '三国演义', '19', '罗贯中', '历史'); 44 | INSERT INTO `book` VALUES (11, '2019-12-26 02:50:41', '2019-12-26 02:50:41', NULL, '三国演义', '19', '罗贯中', '历史'); 45 | INSERT INTO `book` VALUES (12, '2019-12-26 02:50:41', '2019-12-26 02:50:41', NULL, '三国演义', '19', '罗贯中', '历史'); 46 | 47 | -- ---------------------------- 48 | -- Table structure for user 49 | -- ---------------------------- 50 | DROP TABLE IF EXISTS `user`; 51 | CREATE TABLE `user` ( 52 | `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, 53 | `created_at` timestamp(0) NULL DEFAULT NULL, 54 | `updated_at` timestamp(0) NULL DEFAULT NULL, 55 | `deleted_at` timestamp(0) NULL DEFAULT NULL, 56 | `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 57 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 58 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 59 | `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 60 | `mobile` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 61 | `qq` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 62 | `gender` int(11) NULL DEFAULT NULL, 63 | `age` int(11) NULL DEFAULT NULL, 64 | `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 65 | PRIMARY KEY (`id`) USING BTREE, 66 | UNIQUE INDEX `username`(`username`) USING BTREE, 67 | INDEX `idx_user_deleted_at`(`deleted_at`) USING BTREE 68 | ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 69 | 70 | -- ---------------------------- 71 | -- Records of user 72 | -- ---------------------------- 73 | INSERT INTO `user` VALUES (1, '2019-12-26 02:45:35', '2019-12-26 02:45:35', NULL, 'test', 'e10adc3949ba59abbe56e057f20f883e', '', '', '', '', 0, 0, ''); 74 | INSERT INTO `user` VALUES (2, '2019-12-26 02:45:45', '2019-12-26 02:45:45', NULL, 'percy', 'e10adc3949ba59abbe56e057f20f883e', '', '', '', '', 0, 0, ''); 75 | 76 | SET FOREIGN_KEY_CHECKS = 1; 77 | -------------------------------------------------------------------------------- /db/iris-gorm-demo.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "7fb206d4-8547-4162-ab3a-2a369326d496", 4 | "name": "iris-gorm-demo", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "登录", 10 | "request": { 11 | "auth": { 12 | "type": "bearer", 13 | "bearer": [ 14 | { 15 | "key": "token", 16 | "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjUxNzgyOTksImlhdCI6MTU2NTE0MjI5OSwiaWQiOjEsImlzcyI6IklyaXMiLCJqdGkiOiI5NTI3Iiwibmlja19uYW1lIjoicGVyY3kiLCJzZXNzaW9uIjoiIn0.HYHfYpX78GqqqwHV0PSNzJKDIyESoh-Hlvime7JigC0", 17 | "type": "string" 18 | } 19 | ] 20 | }, 21 | "method": "POST", 22 | "header": [ 23 | { 24 | "key": "Content-Type", 25 | "name": "Content-Type", 26 | "value": "application/json", 27 | "type": "text" 28 | } 29 | ], 30 | "body": { 31 | "mode": "raw", 32 | "raw": "{\n\t\"username\":\"test\",\n\t\"password\":\"123456\"\n}" 33 | }, 34 | "url": { 35 | "raw": "localhost:8848/api/user/login", 36 | "host": [ 37 | "localhost" 38 | ], 39 | "port": "8848", 40 | "path": [ 41 | "api", 42 | "user", 43 | "login" 44 | ] 45 | } 46 | }, 47 | "response": [] 48 | }, 49 | { 50 | "name": "注册", 51 | "request": { 52 | "method": "POST", 53 | "header": [ 54 | { 55 | "key": "Content-Type", 56 | "name": "Content-Type", 57 | "value": "application/json", 58 | "type": "text" 59 | } 60 | ], 61 | "body": { 62 | "mode": "raw", 63 | "raw": "{\n\t\"username\":\"test\",\n\t\"password\":\"123456\"\n}", 64 | "options": { 65 | "raw": { 66 | "language": "json" 67 | } 68 | } 69 | }, 70 | "url": { 71 | "raw": "localhost:8848/api/user/save", 72 | "host": [ 73 | "localhost" 74 | ], 75 | "port": "8848", 76 | "path": [ 77 | "api", 78 | "user", 79 | "save" 80 | ] 81 | } 82 | }, 83 | "response": [] 84 | }, 85 | { 86 | "name": "list", 87 | "request": { 88 | "auth": { 89 | "type": "bearer", 90 | "bearer": [ 91 | { 92 | "key": "token", 93 | "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzczNjM3MzEsImlhdCI6MTU3NzMyNzczMSwiaWQiOjEsImlzcyI6IklyaXMiLCJqdGkiOiI5NTI3Iiwibmlja19uYW1lIjoicGVyY3kiLCJzZXNzaW9uIjoiIn0.TjfHEIEMvYqWXWWOWU0ZELl5rJV_d0d0sGgY8Gf8g2U", 94 | "type": "string" 95 | } 96 | ] 97 | }, 98 | "method": "POST", 99 | "header": [ 100 | { 101 | "key": "Content-Type", 102 | "name": "Content-Type", 103 | "value": "application/json", 104 | "type": "text" 105 | } 106 | ], 107 | "body": { 108 | "mode": "raw", 109 | "raw": "{\n\t\"page\":\"1\",\n\t\"size\":\"10\"\n}", 110 | "options": { 111 | "raw": { 112 | "language": "json" 113 | } 114 | } 115 | }, 116 | "url": { 117 | "raw": "localhost:8848/api/book/list", 118 | "host": [ 119 | "localhost" 120 | ], 121 | "port": "8848", 122 | "path": [ 123 | "api", 124 | "book", 125 | "list" 126 | ] 127 | } 128 | }, 129 | "response": [] 130 | }, 131 | { 132 | "name": "save", 133 | "request": { 134 | "auth": { 135 | "type": "bearer", 136 | "bearer": [ 137 | { 138 | "key": "token", 139 | "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzczNjM3MzEsImlhdCI6MTU3NzMyNzczMSwiaWQiOjEsImlzcyI6IklyaXMiLCJqdGkiOiI5NTI3Iiwibmlja19uYW1lIjoicGVyY3kiLCJzZXNzaW9uIjoiIn0.TjfHEIEMvYqWXWWOWU0ZELl5rJV_d0d0sGgY8Gf8g2U", 140 | "type": "string" 141 | } 142 | ] 143 | }, 144 | "method": "POST", 145 | "header": [ 146 | { 147 | "key": "Content-Type", 148 | "name": "Content-Type", 149 | "value": "application/json", 150 | "type": "text" 151 | } 152 | ], 153 | "body": { 154 | "mode": "raw", 155 | "raw": "{\n\n\t\"name\": \"三国演义\",\n\t\"count\": \"19\",\n\t\"author\": \"罗贯中\",\n\t\"type\":\"历史\"\n}", 156 | "options": { 157 | "raw": { 158 | "language": "json" 159 | } 160 | } 161 | }, 162 | "url": { 163 | "raw": "localhost:8848/api/book/save", 164 | "host": [ 165 | "localhost" 166 | ], 167 | "port": "8848", 168 | "path": [ 169 | "api", 170 | "book", 171 | "save" 172 | ] 173 | } 174 | }, 175 | "response": [] 176 | }, 177 | { 178 | "name": "del", 179 | "request": { 180 | "auth": { 181 | "type": "bearer", 182 | "bearer": [ 183 | { 184 | "key": "token", 185 | "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzczNjQzNDksImlhdCI6MTU3NzMyODM0OSwiaWQiOjEsImlzcyI6IklyaXMiLCJqdGkiOiI5NTI3Iiwibmlja19uYW1lIjoidGVzdCIsInNlc3Npb24iOiIifQ.lDx-VATbskR27OIe2N2u_4nMbqC8tOXuOulZTmPPHxM", 186 | "type": "string" 187 | } 188 | ] 189 | }, 190 | "method": "POST", 191 | "header": [ 192 | { 193 | "key": "Content-Type", 194 | "name": "Content-Type", 195 | "value": "application/json", 196 | "type": "text" 197 | } 198 | ], 199 | "body": { 200 | "mode": "raw", 201 | "raw": "{\n\t\"id\":7\n}", 202 | "options": { 203 | "raw": { 204 | "language": "json" 205 | } 206 | } 207 | }, 208 | "url": { 209 | "raw": "localhost:8848/api/book/del", 210 | "host": [ 211 | "localhost" 212 | ], 213 | "port": "8848", 214 | "path": [ 215 | "api", 216 | "book", 217 | "del" 218 | ] 219 | } 220 | }, 221 | "response": [] 222 | }, 223 | { 224 | "name": "get", 225 | "request": { 226 | "auth": { 227 | "type": "bearer", 228 | "bearer": [ 229 | { 230 | "key": "token", 231 | "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzczNjQzNDksImlhdCI6MTU3NzMyODM0OSwiaWQiOjEsImlzcyI6IklyaXMiLCJqdGkiOiI5NTI3Iiwibmlja19uYW1lIjoidGVzdCIsInNlc3Npb24iOiIifQ.lDx-VATbskR27OIe2N2u_4nMbqC8tOXuOulZTmPPHxM", 232 | "type": "string" 233 | } 234 | ] 235 | }, 236 | "method": "POST", 237 | "header": [ 238 | { 239 | "key": "Content-Type", 240 | "name": "Content-Type", 241 | "value": "application/json", 242 | "type": "text" 243 | } 244 | ], 245 | "body": { 246 | "mode": "raw", 247 | "raw": "{\n\t\"id\": \"2\"\n}", 248 | "options": { 249 | "raw": { 250 | "language": "json" 251 | } 252 | } 253 | }, 254 | "url": { 255 | "raw": "localhost:8848/api/book/get", 256 | "host": [ 257 | "localhost" 258 | ], 259 | "port": "8848", 260 | "path": [ 261 | "api", 262 | "book", 263 | "get" 264 | ] 265 | } 266 | }, 267 | "response": [] 268 | } 269 | ], 270 | "protocolProfileBehavior": {} 271 | } -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 65 | 66 | 67 | 68 | ms 69 | utils 70 | fmt 71 | Status 72 | CrossAccess 73 | 74 | 75 | 76 | 77 | 79 | 80 | 101 | 102 | 103 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |