Browse Source

system: 用户登录

Yi 1 year ago
parent
commit
c5dd794ff6

+ 1 - 0
.gitignore

@@ -46,3 +46,4 @@ _testmain.go
 .idea/
 bin/
 .vscode/
+logger

+ 2 - 3
backend/operation/pasture.proto

@@ -9,11 +9,10 @@ message AddPastureRequest {
   int64 id = 1;
   string name = 2; // 牧场名称
   string manager_user = 3; // 牧场负责人名称
-  string manager_password = 4; // 牧场负责人账号
   string manager_phone = 5;   // 牧场负责人手机号
   string address = 6;   // 牧场地址
   IsShow.Kind is_show = 7;    // 是否启用
-  int64 Created_at = 8;    // 创建时间
+  int64 created_at = 8;    // 创建时间
 }
 
 message SearchPastureRequest {
@@ -29,5 +28,5 @@ message SearchPastureRequest {
 message SearchPastureResponse {
   int32 page = 1;
   int32 total = 2;
-  repeated AddPastureRequest data = 3;
+  repeated AddPastureRequest list = 3;
 }

+ 30 - 0
backend/operation/system.proto

@@ -12,3 +12,33 @@ message AddRoleRequest {
   IsShow is_show = 4;   // 是否启用
 }
 
+message SearchRoleRequest {
+  int32 page = 1;        // 第几页,从1开始
+  int32 page_size = 2;   // 每页size,一般为20
+  string name = 3;       // 角色名称
+}
+
+message SearchRoleResponse {
+  int32 page = 1;
+  int32 total = 2;
+  repeated AddRoleRequest list = 3;
+}
+
+
+message AddMenuRequest {
+  int64 id = 1;
+  string name = 2;
+}
+
+// 用户token
+message SystemToken {
+  string token = 1;
+}
+
+message UserAuth {
+  string user_name = 1;   // 用户名称
+  string password = 2;    // 用户密码
+  string phone = 3;       // 用户手机号
+  int64  role_id  = 4;    // 用户角色id
+  string  role_name = 5;  // 用户角色名称
+}

+ 15 - 0
config/app.go

@@ -25,6 +25,9 @@ type AppConfig struct {
 
 	// 数据库配置 额外加载文件部分 database.yaml
 	StoreSetting StoreSetting `json:"storeSetting" yaml:"store"`
+	// redis 配置
+	RedisSetting RedisSetting `json:"RedisSetting" yaml:"redis_setting"`
+	JwtSecret    string       `json:"jwtSecret" yaml:"jwt_secret"`
 }
 
 // StoreSetting 数据库配置
@@ -36,6 +39,18 @@ type StoreSetting struct {
 	KptEventDSNMigr string `yaml:"kpt_tmr_group_migr" env:"LINGO_COURSE_DSN_MIGR"`
 }
 
+type RedisSetting struct {
+	// sso 配置
+	SSOCache SSOCache `json:"SSOCache" yaml:"sso_cache"`
+}
+
+type SSOCache struct {
+	Addr        string `json:"addr" yaml:"addr"`
+	Requirepass string `json:"requirepass" yaml:"requirepass"`
+	DB          int    `json:"DB" yaml:"DB"`
+	Expiry      int    `json:"expiry" yaml:"expiry"`
+}
+
 func Options() *AppConfig {
 	return options
 }

+ 9 - 0
config/app.test.yaml

@@ -9,3 +9,12 @@ store:
   driver_name: mysql
   kpt_tmr_group_rw: "root:123456@tcp(127.0.0.1:3306)/kpt_tmr_group?charset=utf8mb4&parseTime=true&loc=Local&allowNativePasswords=true&timeout=300s&readTimeout=300s&writeTimeout=300s"
   kpt_tmr_group_migr: "root:123456@tcp(127.0.0.1:3306)/kpt_tmr_group?charset=utf8mb4&parseTime=true&loc=Local&allowNativePasswords=true&timeout=300s&readTimeout=300s&writeTimeout=300s"
+
+redis_setting:
+  sso_cache:
+    addr: 192.168.1.70:6379
+    db: 12
+    requirepass: ""
+    expiry: 120
+
+jwt_secret: "sUd7j%UfJMt59ywh"

+ 2 - 0
dep/dep.go

@@ -4,6 +4,7 @@ import (
 	"kpt-tmr-group/config"
 	"kpt-tmr-group/module/backend"
 	"kpt-tmr-group/pkg/di"
+	"kpt-tmr-group/service/sso"
 	"kpt-tmr-group/store/kptstore"
 )
 
@@ -23,5 +24,6 @@ func Options() []di.HubOption {
 		// store
 		kptstore.Module,
 		backend.Module,
+		sso.Module,
 	}
 }

+ 5 - 2
go.mod

@@ -3,17 +3,19 @@ module kpt-tmr-group
 go 1.17
 
 require (
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/getsentry/sentry-go v0.20.0
 	github.com/gin-contrib/cors v1.4.0
 	github.com/gin-contrib/gzip v0.0.6
 	github.com/gin-contrib/requestid v0.0.6
 	github.com/gin-gonic/gin v1.9.0
+	github.com/go-redis/redis v6.15.9+incompatible
+	github.com/go-redis/redis/v7 v7.4.1
 	github.com/google/go-cmp v0.5.9
 	github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/jinzhu/copier v0.3.5
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
-	github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/natefinch/lumberjack v2.0.0+incompatible
 	github.com/sirupsen/logrus v1.9.0
@@ -22,6 +24,7 @@ require (
 	github.com/stretchr/testify v1.8.2
 	go.uber.org/dig v1.15.0
 	go.uber.org/zap v1.21.0
+	golang.org/x/oauth2 v0.5.0
 	google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef
 	google.golang.org/grpc v1.52.0
 	google.golang.org/protobuf v1.30.0
@@ -55,7 +58,6 @@ require (
 	github.com/lestrrat-go/strftime v1.0.6 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mattn/go-isatty v0.0.17 // indirect
-	github.com/mattn/go-sqlite3 v1.14.16 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -80,6 +82,7 @@ require (
 	golang.org/x/net v0.8.0 // indirect
 	golang.org/x/sys v0.6.0 // indirect
 	golang.org/x/text v0.8.0 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect

+ 28 - 4
go.sum

@@ -64,6 +64,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -71,6 +73,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ=
@@ -103,6 +106,10 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
 github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
 github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
+github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
+github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
+github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -181,6 +188,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -219,15 +228,11 @@ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkL
 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
 github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ=
 github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw=
-github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk=
-github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
 github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
-github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -239,6 +244,11 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
 github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
 github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
@@ -376,6 +386,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -386,6 +397,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -417,6 +429,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -429,6 +443,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -439,6 +454,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -566,6 +582,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -641,14 +658,21 @@ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cn
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

+ 26 - 0
http/handler/system/menu.go

@@ -0,0 +1,26 @@
+package system
+
+import (
+	"kpt-tmr-group/http/middleware"
+	"kpt-tmr-group/pkg/apierr"
+	"kpt-tmr-group/pkg/apiok"
+	operationPb "kpt-tmr-group/proto/go/backend/operation"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+)
+
+func AddMenu(c *gin.Context) {
+
+	req := make([]*operationPb.AddRoleRequest, 0)
+	if err := c.BindJSON(&req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	if err := middleware.BackendOperation(c).OpsService.CreateSystemRoleList(c, req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, apiok.CommonResponse(apiok.NewApiOk(true)))
+}

+ 27 - 0
http/handler/system/user.go

@@ -1,13 +1,40 @@
 package system
 
 import (
+	"kpt-tmr-group/http/middleware"
+	"kpt-tmr-group/pkg/apierr"
 	"kpt-tmr-group/pkg/apiok"
+	operationPb "kpt-tmr-group/proto/go/backend/operation"
 	"net/http"
 
 	"github.com/gin-gonic/gin"
 )
 
+func Auth(c *gin.Context) {
+	req := &operationPb.UserAuth{}
+	if err := c.BindJSON(req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.Auth(c, req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	c.JSON(http.StatusOK, apiok.CommonResponse(res))
+}
+
 func AddUser(c *gin.Context) {
 
 	c.JSON(http.StatusOK, apiok.CommonResponse(apiok.NewApiOk(true)))
 }
+
+func GetUserInfo(c *gin.Context) {
+	res, err := middleware.BackendOperation(c).OpsService.GetUserInfo(c, middleware.GetToken(c))
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, apiok.CommonResponse(res))
+}

+ 11 - 5
http/middleware/pagination.go

@@ -7,19 +7,25 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
+const (
+	Page       = "page"
+	PageSize   = "pageSize"
+	PageOffset = "pageOffset"
+)
+
 // Pagination sets page, pageSize and pageOffset to *gin.Context
 func Pagination() gin.HandlerFunc {
 	return func(c *gin.Context) {
-		page := getSetItem(c, "page", 1)
-		size := getSetItem(c, "pageSize", 20)
-		c.Set("pageOffset", (page-1)*size)
+		page := getSetItem(c, Page, 1)
+		size := getSetItem(c, PageSize, 20)
+		c.Set(PageOffset, (page-1)*size)
 		c.Next()
 	}
 }
 
 func getSetItem(c *gin.Context, k string, d int) int {
 	var n int
-	if v := c.Query(k); v != "" {
+	if v := c.Request.Header.Get(k); v != "" {
 		if i, err := strconv.Atoi(v); err == nil {
 			if i > 0 {
 				n = i
@@ -32,6 +38,6 @@ func getSetItem(c *gin.Context, k string, d int) int {
 	}
 
 	c.Set(k, n)
-	c.Request.URL.Query().Set(k, fmt.Sprintf("%d", n))
+	c.Request.Header.Set(k, fmt.Sprintf("%d", n))
 	return n
 }

+ 50 - 0
http/middleware/sso.go

@@ -0,0 +1,50 @@
+package middleware
+
+import (
+	"kpt-tmr-group/pkg/apierr"
+	"kpt-tmr-group/pkg/jwt"
+	commonPb "kpt-tmr-group/proto/go/backend/common"
+
+	"net/http"
+	"strings"
+
+	"github.com/gin-gonic/gin"
+)
+
+const (
+	Authorization = "Authorization"
+	ToKenPrefix   = "Bearer "
+	UserName      = "userName"
+)
+
+func GetToken(c *gin.Context) string {
+	value := c.Request.Header.Get(Authorization)
+	if value != "" && strings.HasPrefix(value, ToKenPrefix) {
+		return strings.TrimPrefix(value, ToKenPrefix)
+	}
+	return ""
+}
+
+func unauthorized(c *gin.Context) {
+	c.AbortWithStatusJSON(http.StatusBadRequest, apierr.WithContext(c, commonPb.Error_UNAUTHORIZED))
+}
+
+// RequireAdmin ...
+func RequireAdmin() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		token := GetToken(c)
+		if token == "" {
+			unauthorized(c)
+			return
+		}
+
+		claims, err := jwt.ParseToken(token)
+		if err != nil || claims == nil || claims.Username == "" {
+			unauthorized(c)
+			return
+		}
+
+		c.Set(UserName, claims.Username)
+		c.Next()
+	}
+}

+ 8 - 2
http/route/app_api.go

@@ -4,6 +4,7 @@ import (
 	"kpt-tmr-group/http/handler"
 	"kpt-tmr-group/http/handler/pasture"
 	"kpt-tmr-group/http/handler/system"
+	"kpt-tmr-group/http/middleware"
 
 	"github.com/gin-gonic/gin"
 )
@@ -18,10 +19,15 @@ func AppAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		// Health Check
 		s.GET("/check", handler.Health)
 
+		s.POST("/auth", system.Auth)
+
 		// system API 组
 		lingoRoute := authRouteGroup(s, "/api/v1/system/")
+		lingoRoute.POST("/user_info", system.GetUserInfo)
 		lingoRoute.POST("/user/add", system.AddUser)
 
+		lingoRoute.POST("/role/add", system.AddRole)
+
 		// 牧场管理
 		lingoRoute.POST("/pasture/add", pasture.AddPasture)
 		lingoRoute.POST("/pasture/list", pasture.SearchPastureList)
@@ -30,7 +36,7 @@ func AppAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 
 func authRouteGroup(s *gin.Engine, relativePath string) *gin.RouterGroup {
 	group := s.Group(relativePath)
-	// TODO 中间件鉴权
-	// group.Use(middleware.Auth(), m.UserKitMiddleware())
+	// 中间件鉴权
+	group.Use(middleware.RequireAdmin(), middleware.Pagination())
 	return group
 }

+ 0 - 53
logger/logrus-2023-05-06.log

@@ -1,53 +0,0 @@
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T16:51:38+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/store/kptstore/rw_store.go:47\n[error] failed to initialize database, got error Error 1045 (28000): Access denied for user 'root'@'172.19.0.1' (using password: NO)","time":"2023-05-06T16:51:38+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T16:54:30+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/store/kptstore/rw_store.go:47\n[error] failed to initialize database, got error Error 1049 (42000): Unknown database 'kpt_tmr-group'","time":"2023-05-06T16:54:30+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T16:54:56+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/store/kptstore/rw_store.go:47\n[error] failed to initialize database, got error Error 1049 (42000): Unknown database 'kpt_tmr-group'","time":"2023-05-06T16:54:56+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T16:55:18+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T16:55:18+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T17:59:10+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T17:59:10+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[66.660ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:06:55+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[5.984ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:06:55+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:09:56+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:09:56+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[15.212ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:10:01+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[6.141ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:10:01+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[4.496ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:11:22+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[3.826ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:11:22+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[2.234ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:11:22+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[3.514ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:11:22+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[5.620ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:11:23+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.685ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:11:23+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:12:14+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:12:14+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[9.825ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:12:24+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.170ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:12:24+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[2.756ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:12:26+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[1.601ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:12:26+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[2.269ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:12:27+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[1.699ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:12:27+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:12:54+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:12:54+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[8.080ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:13:13+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[3.225ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:13:13+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:14:27+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:14:27+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[10.386ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:14:32+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.703ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:14:32+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:15:01+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:15:01+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[15.669ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:15:06+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.203ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:15:06+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:16:02+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:16:02+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[15.813ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:16:06+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.120ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:16:06+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[4.555ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:16:08+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[3.303ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:16:08+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:38\n[2.195ms] [rows:1] SELECT count(*) FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%'","time":"2023-05-06T18:18:12+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:39\n[2.724ms] [rows:0] SELECT * FROM `group_pasture` WHERE is_show = 1  AND name like '%现代牧业%' ORDER BY id desc LIMIT 10","time":"2023-05-06T18:18:12+08:00"}
-{"level":"info","msg":"kpe-event: is starting","time":"2023-05-06T18:27:20+08:00"}
-{"level":"info","msg":"kpt-tmr-group: boot HTTP server","time":"2023-05-06T18:27:21+08:00"}
-{"level":"info","msg":"D:/project/golangNew/kpt-tmr-group/module/backend/service.go:14 Error 1265 (01000): Data truncated for column 'created_at' at row 1\n[31.262ms] [rows:0] INSERT INTO `group_pasture` (`name`,`manager_user`,`manager_password`,`manager_phone`,`is_show`,`address`,`created_at`,`updated_at`) VALUES ('选地低识要','officia cillum','e10adc3949ba59abbe56e057f20f883e','18642558992',1,'福建省汕尾市巴林左旗','2023-05-06 18:27:26.506','2023-05-06 18:27:26.506'),('种切命','minim Duis sint aliqua deserunt','e10adc3949ba59abbe56e057f20f883e','18135781774',1,'贵州省七台河市贵南县','2023-05-06 18:27:26.506','2023-05-06 18:27:26.506')","time":"2023-05-06T18:27:26+08:00"}

+ 18 - 20
model/group_pasture.go

@@ -21,7 +21,7 @@ func (s *GroupPasture) TableName() string {
 	return "group_pasture"
 }
 
-const InitPassword = "123456"
+const InitManagerPassword = "123456"
 
 func NewGroupPastureList(reqs []*operationPb.AddPastureRequest) []*GroupPasture {
 	groupPastureList := make([]*GroupPasture, len(reqs))
@@ -29,7 +29,7 @@ func NewGroupPastureList(reqs []*operationPb.AddPastureRequest) []*GroupPasture
 		groupPastureList[k] = &GroupPasture{
 			Name:            pasture.Name,
 			ManagerUser:     pasture.ManagerUser,
-			ManagerPassword: tool.Md5String(InitPassword),
+			ManagerPassword: tool.Md5String(InitManagerPassword),
 			ManagerPhone:    pasture.ManagerPhone,
 			IsShow:          operationPb.IsShow_OK,
 			Address:         pasture.Address,
@@ -44,14 +44,13 @@ func (g GroupPastureSlice) ToPB() []*operationPb.AddPastureRequest {
 	res := make([]*operationPb.AddPastureRequest, len(g))
 	for i, v := range g {
 		res[i] = &operationPb.AddPastureRequest{
-			Id:              v.Id,
-			Name:            v.Name,
-			ManagerUser:     v.ManagerUser,
-			ManagerPassword: v.ManagerPassword,
-			ManagerPhone:    v.ManagerPhone,
-			Address:         v.ManagerPassword,
-			IsShow:          v.IsShow,
-			CreatedAt:       v.CreatedAt,
+			Id:           v.Id,
+			Name:         v.Name,
+			ManagerUser:  v.ManagerUser,
+			ManagerPhone: v.ManagerPhone,
+			Address:      v.Address,
+			IsShow:       v.IsShow,
+			CreatedAt:    v.CreatedAt,
 		}
 	}
 	return res
@@ -59,27 +58,26 @@ func (g GroupPastureSlice) ToPB() []*operationPb.AddPastureRequest {
 
 func (g *GroupPasture) ToPb() *operationPb.AddPastureRequest {
 	return &operationPb.AddPastureRequest{
-		Id:              g.Id,
-		Name:            g.Name,
-		ManagerUser:     g.ManagerUser,
-		ManagerPassword: g.ManagerPassword,
-		ManagerPhone:    g.ManagerPhone,
-		Address:         g.Address,
-		IsShow:          g.IsShow,
-		CreatedAt:       g.CreatedAt,
+		Id:           g.Id,
+		Name:         g.Name,
+		ManagerUser:  g.ManagerUser,
+		ManagerPhone: g.ManagerPhone,
+		Address:      g.Address,
+		IsShow:       g.IsShow,
+		CreatedAt:    g.CreatedAt,
 	}
 }
 
 type GroupPastureResponse struct {
 	Page  int32                            `json:"page"`
 	Total int32                            `json:"total"`
-	Data  []*operationPb.AddPastureRequest `json:"data"`
+	List  []*operationPb.AddPastureRequest `json:"list"`
 }
 
 func (g *GroupPastureResponse) ToPB() *operationPb.SearchPastureResponse {
 	return &operationPb.SearchPastureResponse{
 		Page:  g.Page,
 		Total: g.Total,
-		Data:  g.Data,
+		List:  g.List,
 	}
 }

+ 4 - 2
model/system_menu.go

@@ -7,13 +7,15 @@ import (
 type SystemMenu struct {
 	Id        int64                   `json:"id,omitempty"`
 	Name      string                  `json:"name,omitempty"`
-	MenuType  int                     `json:"menu_type,omitempty"`
+	MenuType  int32                   `json:"menu_type,omitempty"`
+	GroupType int32                   `json:"group_type,omitempty"`
 	Title     string                  `json:"title,omitempty"`
 	Path      string                  `json:"path,omitempty"`
 	IsShow    operationPb.IsShow_Kind `json:"is_show,omitempty"`
 	Component string                  `json:"component,omitempty"`
 	Icon      string                  `json:"icon,omitempty"`
-	Sort      int                     `json:"sort,omitempty"`
+	Sort      int32                   `json:"sort,omitempty"`
+	ParentId  int64                   `json:"parent_id"`
 	Redirect  string                  `json:"redirect,omitempty"`
 	CreatedAt int64                   `json:"created_at,omitempty"`
 	UpdatedAt int64                   `json:"updated_at,omitempty"`

+ 21 - 7
model/system_role.go

@@ -5,15 +5,29 @@ import (
 )
 
 type SystemRole struct {
-	Id         int64                   `json:"id,omitempty"`
-	Name       string                  `json:"name,omitempty"`
-	Remarks    string                  `json:"remarks,omitempty"`
-	IsShow     operationPb.IsShow_Kind `json:"is_show,omitempty"`
-	CreateUser string                  `json:"create_user,omitempty"`
-	CreatedAt  int64                   `json:"created_at,omitempty"`
-	UpdatedAt  int64                   `json:"updated_at,omitempty"`
+	Id          int64                   `json:"id,omitempty"`
+	Name        string                  `json:"name,omitempty"`
+	Remarks     string                  `json:"remarks,omitempty"`
+	IsShow      operationPb.IsShow_Kind `json:"is_show,omitempty"`
+	PastureId   int64                   `json:"pasture_id"`
+	PastureName string                  `json:"pasture_name"`
+	CreateUser  string                  `json:"create_user,omitempty"`
+	CreatedAt   int64                   `json:"created_at,omitempty"`
+	UpdatedAt   int64                   `json:"updated_at,omitempty"`
 }
 
 func (s *SystemRole) TableName() string {
 	return "system_role"
 }
+
+func NewSystemRoleList(reqs []*operationPb.AddRoleRequest) []*SystemRole {
+	systemRoleList := make([]*SystemRole, len(reqs))
+	for k, role := range reqs {
+		systemRoleList[k] = &SystemRole{
+			Name:    role.Name,
+			Remarks: role.Remarks,
+			IsShow:  operationPb.IsShow_OK,
+		}
+	}
+	return systemRoleList
+}

+ 13 - 1
model/system_user.go

@@ -7,7 +7,9 @@ import (
 type SystemUser struct {
 	Id         int64                   `json:"id,omitempty"`
 	Name       string                  `json:"name,omitempty"`
-	RoleId     int                     `json:"role_id,omitempty"`
+	Phone      string                  `json:"phone"`
+	Password   string                  `json:"password"`
+	RoleId     int64                   `json:"role_id,omitempty"`
 	RoleName   string                  `json:"role_name,omitempty"`
 	CreateUser string                  `json:"create_user,omitempty"`
 	IsShow     operationPb.IsShow_Kind `json:"is_show,omitempty"`
@@ -18,3 +20,13 @@ type SystemUser struct {
 func (s *SystemUser) TableName() string {
 	return "system_user"
 }
+
+func (s *SystemUser) SystemUserFormat() *operationPb.UserAuth {
+	return &operationPb.UserAuth{
+		UserName: s.Name,
+		Password: s.Password,
+		Phone:    s.Phone,
+		RoleId:   s.RoleId,
+		RoleName: s.RoleName,
+	}
+}

+ 10 - 3
module/backend/interface.go

@@ -11,9 +11,7 @@ import (
 	"go.uber.org/dig"
 )
 
-var Module = di.Options(
-	di.Provide(NewStore),
-)
+var Module = di.Options(di.Provide(NewStore))
 
 type Hub struct {
 	dig.In
@@ -25,6 +23,7 @@ type StoreEntry struct {
 
 	Cfg *config.AppConfig
 	DB  *kptstore.DB
+	//SSO *sso.Cache
 	// AsynqClient asynqsvc.Client
 	// Cache *redis.Client
 }
@@ -35,10 +34,18 @@ func NewStore(store StoreEntry) KptService {
 
 type KptService interface {
 	Operation
+	SSOAuth
 }
 
 type Operation interface {
+	CreateSystemRoleList(ctx context.Context, req []*operationPb.AddRoleRequest) error
+
 	// CreatePastureList 牧场管理相关
 	CreatePastureList(ctx context.Context, req []*operationPb.AddPastureRequest) error
 	SearchPastureList(ctx context.Context, req *operationPb.SearchPastureRequest) (*model.GroupPastureResponse, error)
 }
+
+type SSOAuth interface {
+	Auth(ctx context.Context, auth *operationPb.UserAuth) (*operationPb.SystemToken, error)
+	GetUserInfo(ctx context.Context, token string) (*operationPb.UserAuth, error)
+}

+ 21 - 3
module/backend/service.go → module/backend/ops_service.go

@@ -8,10 +8,28 @@ import (
 	operationPb "kpt-tmr-group/proto/go/backend/operation"
 )
 
+// CreateSystemRoleList 添加角色
+func (s *StoreEntry) CreateSystemRoleList(ctx context.Context, req []*operationPb.AddRoleRequest) error {
+	roleList := model.NewSystemRoleList(req)
+	if err := s.DB.Create(roleList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+// SearchSystemRoleList 查询角色列表
+func (s *StoreEntry) SearchSystemRoleList(ctx context.Context, req []*operationPb.AddRoleRequest) error {
+	roleList := model.NewSystemRoleList(req)
+	if err := s.DB.Create(roleList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
 // CreatePastureList 创建牧场
 func (s *StoreEntry) CreatePastureList(ctx context.Context, req []*operationPb.AddPastureRequest) error {
-	pastureListModel := model.NewGroupPastureList(req)
-	if err := s.DB.Create(pastureListModel).Error; err != nil {
+	pastureList := model.NewGroupPastureList(req)
+	if err := s.DB.Create(pastureList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 	return nil
@@ -43,6 +61,6 @@ func (s *StoreEntry) SearchPastureList(ctx context.Context, req *operationPb.Sea
 	return &model.GroupPastureResponse{
 		Page:  req.Page,
 		Total: int32(count),
-		Data:  model.GroupPastureSlice(groupPasture).ToPB(),
+		List:  model.GroupPastureSlice(groupPasture).ToPB(),
 	}, nil
 }

+ 51 - 0
module/backend/sso_service.go

@@ -0,0 +1,51 @@
+package backend
+
+import (
+	"context"
+	"kpt-tmr-group/model"
+	"kpt-tmr-group/pkg/jwt"
+	"kpt-tmr-group/pkg/xerr"
+	operationPb "kpt-tmr-group/proto/go/backend/operation"
+)
+
+// Auth 用户登录
+func (s *StoreEntry) Auth(ctx context.Context, auth *operationPb.UserAuth) (*operationPb.SystemToken, error) {
+	systemUser := &model.SystemUser{}
+
+	if err := s.DB.Where("name = ?", auth.UserName).Find(systemUser).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	if systemUser.Password != auth.Password {
+		return nil, xerr.Customf("密码错误,来自用户:%s", auth.UserName)
+	}
+
+	token, err := jwt.GenerateToken(systemUser.Name, systemUser.Password)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	if token == "" {
+		return nil, xerr.Custom("获取token错误")
+	}
+
+	return &operationPb.SystemToken{
+		Token: token,
+	}, nil
+}
+
+// GetUserInfo 获取用户信息
+func (s *StoreEntry) GetUserInfo(ctx context.Context, token string) (*operationPb.UserAuth, error) {
+	systemUser := &model.SystemUser{}
+	claims, err := jwt.ParseToken(token)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	if claims.Username == "" {
+		return nil, xerr.Custom("token解析失败")
+	}
+
+	if err = s.DB.Where("name = ?", claims.Username).Find(systemUser).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return systemUser.SystemUserFormat(), nil
+}

+ 6 - 6
pkg/apiok/common.go

@@ -1,16 +1,16 @@
 package apiok
 
 type OkResponse struct {
-	Code   int         `json:"code"`
-	Msg    string      `json:"msg"`
-	Result interface{} `json:"result"`
+	Code int         `json:"code"`
+	Msg  string      `json:"msg"`
+	Data interface{} `json:"data"`
 }
 
 func CommonResponse(data interface{}) *OkResponse {
 	return &OkResponse{
-		Code:   200,
-		Msg:    "ok",
-		Result: data,
+		Code: 200,
+		Msg:  "ok",
+		Data: data,
 	}
 }
 

+ 64 - 0
pkg/jwt/jwt.go

@@ -0,0 +1,64 @@
+package jwt
+
+import (
+	"fmt"
+	"kpt-tmr-group/config"
+	"kpt-tmr-group/pkg/tool"
+	"reflect"
+	"time"
+
+	"github.com/dgrijalva/jwt-go"
+)
+
+var jwtSecret = []byte(config.Options().JwtSecret)
+
+type Claims struct {
+	Username string `json:"username"`
+	Password string `json:"password"`
+	jwt.StandardClaims
+}
+
+func GenerateToken(username, password string) (string, error) {
+	nowTime := time.Now()
+	expireTime := nowTime.Add(2 * time.Hour)
+
+	claims := Claims{
+		username,
+		tool.Md5String(password),
+		jwt.StandardClaims{
+			ExpiresAt: expireTime.Unix(),
+			Issuer:    "https://github.com/kptyun/go-admin/",
+		},
+	}
+
+	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+	return tokenClaims.SignedString(jwtSecret)
+}
+
+func ParseToken(token string) (*Claims, error) {
+	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
+		return jwtSecret, nil
+	})
+
+	if tokenClaims != nil {
+		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
+			return claims, nil
+		}
+	}
+
+	return nil, err
+}
+
+func GetIdFromClaims(key string, claims jwt.Claims) string {
+	v := reflect.ValueOf(claims)
+	if v.Kind() == reflect.Map {
+		for _, k := range v.MapKeys() {
+			value := v.MapIndex(k)
+
+			if fmt.Sprintf("%s", k.Interface()) == key {
+				return fmt.Sprintf("%v", value.Interface())
+			}
+		}
+	}
+	return ""
+}

+ 1 - 176
pkg/tool/tool.go

@@ -4,7 +4,6 @@ import (
 	"crypto/md5"
 	"encoding/hex"
 	"fmt"
-	"reflect"
 	"strconv"
 	"strings"
 	"time"
@@ -49,97 +48,6 @@ func GetLocalTime(timeStr string) time.Time {
 	return execTime
 }
 
-// GetTargetByValueForTag 利用反射根据cond获取对应字段数据,主要tag必须为gorm
-// e.g person{Name:"ping",Age:12}
-// e.g GetTargetByTag(person,age) ==> 12
-func GetTargetByValueForTag(target interface{}, cond string) interface{} {
-	tf := reflect.Value{}
-	// 判断是不是指针类型
-	if reflect.TypeOf(target).Kind() == reflect.Ptr {
-		if reflect.ValueOf(target).IsNil() { // 空指针
-			return ""
-		}
-		tf = reflect.Indirect(reflect.ValueOf(target))
-	} else {
-		tf = reflect.ValueOf(target)
-	}
-
-	typ := tf.Type()
-	var condValue interface{}
-	for k := 0; k < typ.NumField(); k++ {
-		key := typ.Field(k).Tag.Get("gorm")
-		if key != cond {
-			continue
-		}
-		field := typ.Field(k).Name
-		switch tf.FieldByName(field).Kind() {
-		case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-			condValue = tf.FieldByName(field).Int()
-		case reflect.String:
-			condValue = tf.FieldByName(field).String()
-		}
-	}
-	return condValue
-}
-
-// GetTargetByTypeForTag 利用反射根据cond获取对应的字段类型默认值
-// e.g person{Name:"ping",Age:12,EventStatus: fieldPb.EventStatus_ADMISSION}
-// e.g GetTargetByTypeForTag(person,age) ==> person{Name:"ping",Age:0,EventStatus: fieldPb.EventStatus_ADMISSION}
-// e.g GetTargetByTypeForTag(person,name) ==> person{Name:"",Age:12,EventStatus: fieldPb.EventStatus_ADMISSION}
-// e.g GetTargetByTypeForTag(person,event_status) ==> person{Name:"ping",Age:12,EventStatus: fieldPb.EventStatus_INVALID}
-func GetTargetByTypeForTag(target interface{}, cond string) {
-	tf := reflect.TypeOf(target)
-	// 判断是不是指针类型
-	if tf.Kind() == reflect.Ptr {
-		tf = tf.Elem()
-	}
-	tv := reflect.ValueOf(target)
-	if tv.Kind() == reflect.Ptr {
-		tv = tv.Elem()
-	}
-	for i := 0; i < tf.NumField(); i++ {
-		key := tf.Field(i).Tag.Get("gorm")
-		if key != cond {
-			continue
-		}
-		fieldName := tf.Field(i).Name
-		tfKind := tf.Field(i).Type
-
-		if tfKind.Kind() == reflect.String {
-			tv.FieldByName(fieldName).SetString("")
-		}
-
-		if tfKind.Kind() == reflect.Int || tfKind.Kind() == reflect.Int8 || tfKind.Kind() == reflect.Int16 ||
-			tfKind.Kind() == reflect.Int32 || tfKind.Kind() == reflect.Int64 {
-			tv.FieldByName(fieldName).SetInt(0)
-		}
-
-		if tfKind.Kind() == reflect.Uint || tfKind.Kind() == reflect.Uint8 || tfKind.Kind() == reflect.Uint16 ||
-			tfKind.Kind() == reflect.Uint32 || tfKind.Kind() == reflect.Uint64 {
-			tv.FieldByName(fieldName).SetUint(0)
-		}
-		if tfKind.Kind() == reflect.Float32 || tfKind.Kind() == reflect.Float64 {
-			tv.FieldByName(fieldName).SetFloat(0)
-		}
-	}
-}
-
-// MonthLastDay 获取当月最后一天
-//eg 2023-01 => 2023-01-31
-//eg 2023-02 => 2023-02-28
-func MonthLastDay(yearMonth string) string {
-	item := strings.Split(yearMonth, "-")
-	if len(item) < 2 {
-		return ""
-	}
-
-	year, _ := strconv.Atoi(item[0])
-	loc, _ := time.LoadLocation("Local")
-	theTime, _ := time.ParseInLocation(Layout, fmt.Sprintf("%s-01 00:00:00", yearMonth), loc)
-
-	return time.Date(year, theTime.Month()+1, 0, 0, 0, 0, 0, time.Local).Format("2006-01-02")
-}
-
 // TimeParseLocalUnix 获取当天零点的时间戳
 // eg 2023-02-22 => 1676995200
 func TimeParseLocalUnix(DayTime string) int64 {
@@ -153,92 +61,9 @@ func TimeParseLocalUnix(DayTime string) int64 {
 	return theTime.Unix()
 }
 
-// ColumNameValueJoinSqlString 获取columName对应的值拼接成sql语句
-// eg columName = "a,b,c"  ==> ('1','2','3')
-func ColumNameValueJoinSqlString(columName string, target interface{}) string {
-	columNames := strings.Split(columName, ",")
-	insertValue := "("
-	if target == nil {
-		return insertValue
-	}
-
-	for _, c := range columNames {
-		val := reflect.Value{}
-		if reflect.TypeOf(target).Kind() == reflect.Ptr {
-			val = reflect.Indirect(reflect.ValueOf(target))
-		} else {
-			val = reflect.ValueOf(target)
-		}
-
-		typ := val.Type()
-		strValue := ""
-		for k := 0; k < typ.NumField(); k++ {
-			key := typ.Field(k).Tag.Get("json")
-			key = strings.ReplaceAll(key, ",omitempty", "")
-			if key != c {
-				continue
-			}
-			field := typ.Field(k).Name
-			switch val.FieldByName(field).Kind() {
-			case reflect.String:
-				strValue = fmt.Sprintf("'%s'", val.FieldByName(field).String())
-			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-				strValue = fmt.Sprintf("%d", val.FieldByName(field).Int())
-			case reflect.Float64, reflect.Float32:
-				strValue = fmt.Sprintf("%f", val.FieldByName(field).Float())
-			}
-		}
-
-		insertValue += fmt.Sprintf("%s,", strValue)
-	}
-
-	return fmt.Sprintf("%s)", strings.TrimRight(insertValue, ","))
-}
-
-// ColumNameValue 获取columName 对应的值
-// eg a => 1
-func ColumNameValue(columName string, target interface{}) string {
-	strValue := ""
-	if target == nil {
-		return strValue
-	}
-
-	val := reflect.Value{}
-	if reflect.TypeOf(target).Kind() == reflect.Ptr {
-		val = reflect.Indirect(reflect.ValueOf(target))
-	} else {
-		val = reflect.ValueOf(target)
-	}
-
-	typ := val.Type()
-	for k := 0; k < typ.NumField(); k++ {
-		key := typ.Field(k).Tag.Get("json")
-		key = strings.ReplaceAll(key, ",omitempty", "")
-		if key != columName {
-			continue
-		}
-		field := typ.Field(k).Name
-		switch val.FieldByName(field).Kind() {
-		case reflect.String:
-			strValue = fmt.Sprintf("'%s'", val.FieldByName(field).String())
-		case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-			strValue = fmt.Sprintf("%d", val.FieldByName(field).Int())
-		case reflect.Float64, reflect.Float32:
-			strValue = fmt.Sprintf("%f", val.FieldByName(field).Float())
-		}
-	}
-
-	return strValue
-}
-
-// UnixTimeString unix时间戳转化成string  eg 1673939363 => 2023-01-17
-func UnixTimeString(unixTime int64) string {
-	return time.Unix(unixTime, 0).Format(DateTime)
-}
-
 func Md5String(input string) string {
 	s := md5.New()
-	digest := strings.ReplaceAll(string(input), "\n", "")
+	digest := strings.ReplaceAll(input, "\n", "")
 	s.Write([]byte(digest))
 	return hex.EncodeToString(s.Sum(nil))
 }

+ 0 - 187
proto/go/backend/common/enum.pb.go

@@ -1,187 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.28.1
-// 	protoc        v3.21.9
-// source: backend/common/enum.proto
-
-package commonPb
-
-import (
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	sync "sync"
-)
-
-const (
-	// Verify that this generated code is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
-	// Verify that runtime/protoimpl is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type IsShow_Kind int32
-
-const (
-	IsShow_INVALID IsShow_Kind = 0 // 无效
-	IsShow_OK      IsShow_Kind = 1 // 是
-	IsShow_NO      IsShow_Kind = 2 // 否
-)
-
-// Enum value maps for IsShow_Kind.
-var (
-	IsShow_Kind_name = map[int32]string{
-		0: "INVALID",
-		1: "OK",
-		2: "NO",
-	}
-	IsShow_Kind_value = map[string]int32{
-		"INVALID": 0,
-		"OK":      1,
-		"NO":      2,
-	}
-)
-
-func (x IsShow_Kind) Enum() *IsShow_Kind {
-	p := new(IsShow_Kind)
-	*p = x
-	return p
-}
-
-func (x IsShow_Kind) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (IsShow_Kind) Descriptor() protoreflect.EnumDescriptor {
-	return file_backend_common_enum_proto_enumTypes[0].Descriptor()
-}
-
-func (IsShow_Kind) Type() protoreflect.EnumType {
-	return &file_backend_common_enum_proto_enumTypes[0]
-}
-
-func (x IsShow_Kind) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use IsShow_Kind.Descriptor instead.
-func (IsShow_Kind) EnumDescriptor() ([]byte, []int) {
-	return file_backend_common_enum_proto_rawDescGZIP(), []int{0, 0}
-}
-
-// 是否标识
-type IsShow struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-}
-
-func (x *IsShow) Reset() {
-	*x = IsShow{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_backend_common_enum_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *IsShow) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*IsShow) ProtoMessage() {}
-
-func (x *IsShow) ProtoReflect() protoreflect.Message {
-	mi := &file_backend_common_enum_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use IsShow.ProtoReflect.Descriptor instead.
-func (*IsShow) Descriptor() ([]byte, []int) {
-	return file_backend_common_enum_proto_rawDescGZIP(), []int{0}
-}
-
-var File_backend_common_enum_proto protoreflect.FileDescriptor
-
-var file_backend_common_enum_proto_rawDesc = []byte{
-	0x0a, 0x19, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
-	0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x62, 0x61, 0x63,
-	0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x73, 0x22, 0x2d, 0x0a, 0x06, 0x49, 0x73, 0x53, 0x68,
-	0x6f, 0x77, 0x22, 0x23, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e,
-	0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x01, 0x12,
-	0x06, 0x0a, 0x02, 0x4e, 0x4f, 0x10, 0x02, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x3b, 0x63, 0x6f, 0x6d,
-	0x6d, 0x6f, 0x6e, 0x50, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
-	file_backend_common_enum_proto_rawDescOnce sync.Once
-	file_backend_common_enum_proto_rawDescData = file_backend_common_enum_proto_rawDesc
-)
-
-func file_backend_common_enum_proto_rawDescGZIP() []byte {
-	file_backend_common_enum_proto_rawDescOnce.Do(func() {
-		file_backend_common_enum_proto_rawDescData = protoimpl.X.CompressGZIP(file_backend_common_enum_proto_rawDescData)
-	})
-	return file_backend_common_enum_proto_rawDescData
-}
-
-var file_backend_common_enum_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_backend_common_enum_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_backend_common_enum_proto_goTypes = []interface{}{
-	(IsShow_Kind)(0), // 0: backend.ops.IsShow.Kind
-	(*IsShow)(nil),   // 1: backend.ops.IsShow
-}
-var file_backend_common_enum_proto_depIdxs = []int32{
-	0, // [0:0] is the sub-list for method output_type
-	0, // [0:0] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_backend_common_enum_proto_init() }
-func file_backend_common_enum_proto_init() {
-	if File_backend_common_enum_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_backend_common_enum_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*IsShow); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_backend_common_enum_proto_rawDesc,
-			NumEnums:      1,
-			NumMessages:   1,
-			NumExtensions: 0,
-			NumServices:   0,
-		},
-		GoTypes:           file_backend_common_enum_proto_goTypes,
-		DependencyIndexes: file_backend_common_enum_proto_depIdxs,
-		EnumInfos:         file_backend_common_enum_proto_enumTypes,
-		MessageInfos:      file_backend_common_enum_proto_msgTypes,
-	}.Build()
-	File_backend_common_enum_proto = out.File
-	file_backend_common_enum_proto_rawDesc = nil
-	file_backend_common_enum_proto_goTypes = nil
-	file_backend_common_enum_proto_depIdxs = nil
-}

+ 45 - 56
proto/go/backend/operation/pasture.pb.go

@@ -25,14 +25,13 @@ type AddPastureRequest struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Id              int64       `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
-	Name            string      `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`                                                       // 牧场名称
-	ManagerUser     string      `protobuf:"bytes,3,opt,name=manager_user,json=managerUser,proto3" json:"manager_user,omitempty"`                      // 牧场负责人名称
-	ManagerPassword string      `protobuf:"bytes,4,opt,name=manager_password,json=managerPassword,proto3" json:"manager_password,omitempty"`          // 牧场负责人账号
-	ManagerPhone    string      `protobuf:"bytes,5,opt,name=manager_phone,json=managerPhone,proto3" json:"manager_phone,omitempty"`                   // 牧场负责人手机号
-	Address         string      `protobuf:"bytes,6,opt,name=address,proto3" json:"address,omitempty"`                                                 // 牧场地址
-	IsShow          IsShow_Kind `protobuf:"varint,7,opt,name=is_show,json=isShow,proto3,enum=backend.operation.IsShow_Kind" json:"is_show,omitempty"` // 是否启用
-	CreatedAt       int64       `protobuf:"varint,8,opt,name=Created_at,json=CreatedAt,proto3" json:"Created_at,omitempty"`                           // 创建时间
+	Id           int64       `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name         string      `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`                                                       // 牧场名称
+	ManagerUser  string      `protobuf:"bytes,3,opt,name=manager_user,json=managerUser,proto3" json:"manager_user,omitempty"`                      // 牧场负责人名称
+	ManagerPhone string      `protobuf:"bytes,5,opt,name=manager_phone,json=managerPhone,proto3" json:"manager_phone,omitempty"`                   // 牧场负责人手机号
+	Address      string      `protobuf:"bytes,6,opt,name=address,proto3" json:"address,omitempty"`                                                 // 牧场地址
+	IsShow       IsShow_Kind `protobuf:"varint,7,opt,name=is_show,json=isShow,proto3,enum=backend.operation.IsShow_Kind" json:"is_show,omitempty"` // 是否启用
+	CreatedAt    int64       `protobuf:"varint,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`                           // 创建时间
 }
 
 func (x *AddPastureRequest) Reset() {
@@ -88,13 +87,6 @@ func (x *AddPastureRequest) GetManagerUser() string {
 	return ""
 }
 
-func (x *AddPastureRequest) GetManagerPassword() string {
-	if x != nil {
-		return x.ManagerPassword
-	}
-	return ""
-}
-
 func (x *AddPastureRequest) GetManagerPhone() string {
 	if x != nil {
 		return x.ManagerPhone
@@ -225,7 +217,7 @@ type SearchPastureResponse struct {
 
 	Page  int32                `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
 	Total int32                `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
-	Data  []*AddPastureRequest `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty"`
+	List  []*AddPastureRequest `protobuf:"bytes,3,rep,name=list,proto3" json:"list,omitempty"`
 }
 
 func (x *SearchPastureResponse) Reset() {
@@ -274,9 +266,9 @@ func (x *SearchPastureResponse) GetTotal() int32 {
 	return 0
 }
 
-func (x *SearchPastureResponse) GetData() []*AddPastureRequest {
+func (x *SearchPastureResponse) GetList() []*AddPastureRequest {
 	if x != nil {
-		return x.Data
+		return x.List
 	}
 	return nil
 }
@@ -289,48 +281,45 @@ var file_backend_operation_pasture_proto_rawDesc = []byte{
 	0x6f, 0x12, 0x11, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x72, 0x61,
 	0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x6f, 0x70,
 	0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x22, 0x9c, 0x02, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x50, 0x61, 0x73, 0x74, 0x75, 0x72,
+	0x74, 0x6f, 0x22, 0xf1, 0x01, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x50, 0x61, 0x73, 0x74, 0x75, 0x72,
 	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
 	0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
 	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c,
 	0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12,
-	0x29, 0x0a, 0x10, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77,
-	0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x61, 0x6e, 0x61, 0x67,
-	0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61,
-	0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12,
-	0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x69, 0x73, 0x5f,
-	0x73, 0x68, 0x6f, 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x62, 0x61, 0x63,
-	0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49,
-	0x73, 0x53, 0x68, 0x6f, 0x77, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x06, 0x69, 0x73, 0x53, 0x68,
-	0x6f, 0x77, 0x12, 0x1d, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
-	0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41,
-	0x74, 0x22, 0xdd, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x61, 0x73, 0x74,
-	0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
-	0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x1b,
-	0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e,
-	0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
-	0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18,
-	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x55, 0x73,
-	0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x68,
-	0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67,
-	0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74,
-	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61,
-	0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69,
-	0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d,
-	0x65, 0x22, 0x7b, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x61, 0x73, 0x74, 0x75,
-	0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
-	0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x14,
-	0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74,
-	0x6f, 0x74, 0x61, 0x6c, 0x12, 0x38, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x61, 0x73, 0x74, 0x75, 0x72,
-	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0f,
-	0x5a, 0x0d, 0x2e, 0x3b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x62, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50,
+	0x68, 0x6f, 0x6e, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37,
+	0x0a, 0x07, 0x69, 0x73, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x1e, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x73, 0x53, 0x68, 0x6f, 0x77, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52,
+	0x06, 0x69, 0x73, 0x53, 0x68, 0x6f, 0x77, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74,
+	0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xdd, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x50, 0x61, 0x73, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70,
+	0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65,
+	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f,
+	0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x61,
+	0x67, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67,
+	0x65, 0x72, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
+	0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03,
+	0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65,
+	0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x65,
+	0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x7b, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
+	0x50, 0x61, 0x73, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+	0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70,
+	0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x38, 0x0a, 0x04, 0x6c, 0x69, 0x73,
+	0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e,
+	0x64, 0x2e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x50,
+	0x61, 0x73, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x6c,
+	0x69, 0x73, 0x74, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x3b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x50, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -354,7 +343,7 @@ var file_backend_operation_pasture_proto_goTypes = []interface{}{
 }
 var file_backend_operation_pasture_proto_depIdxs = []int32{
 	3, // 0: backend.operation.AddPastureRequest.is_show:type_name -> backend.operation.IsShow.Kind
-	0, // 1: backend.operation.SearchPastureResponse.data:type_name -> backend.operation.AddPastureRequest
+	0, // 1: backend.operation.SearchPastureResponse.list:type_name -> backend.operation.AddPastureRequest
 	2, // [2:2] is the sub-list for method output_type
 	2, // [2:2] is the sub-list for method input_type
 	2, // [2:2] is the sub-list for extension type_name

+ 414 - 12
proto/go/backend/operation/system.pb.go

@@ -92,6 +92,314 @@ func (x *AddRoleRequest) GetIsShow() *IsShow {
 	return nil
 }
 
+type SearchRoleRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Page     int32  `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`                         // 第几页,从1开始
+	PageSize int32  `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页size,一般为20
+	Name     string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`                          // 角色名称
+}
+
+func (x *SearchRoleRequest) Reset() {
+	*x = SearchRoleRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_backend_operation_system_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SearchRoleRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SearchRoleRequest) ProtoMessage() {}
+
+func (x *SearchRoleRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_backend_operation_system_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SearchRoleRequest.ProtoReflect.Descriptor instead.
+func (*SearchRoleRequest) Descriptor() ([]byte, []int) {
+	return file_backend_operation_system_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SearchRoleRequest) GetPage() int32 {
+	if x != nil {
+		return x.Page
+	}
+	return 0
+}
+
+func (x *SearchRoleRequest) GetPageSize() int32 {
+	if x != nil {
+		return x.PageSize
+	}
+	return 0
+}
+
+func (x *SearchRoleRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+type SearchRoleResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Page  int32             `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"`
+	Total int32             `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
+	List  []*AddRoleRequest `protobuf:"bytes,3,rep,name=list,proto3" json:"list,omitempty"`
+}
+
+func (x *SearchRoleResponse) Reset() {
+	*x = SearchRoleResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_backend_operation_system_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SearchRoleResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SearchRoleResponse) ProtoMessage() {}
+
+func (x *SearchRoleResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_backend_operation_system_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SearchRoleResponse.ProtoReflect.Descriptor instead.
+func (*SearchRoleResponse) Descriptor() ([]byte, []int) {
+	return file_backend_operation_system_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SearchRoleResponse) GetPage() int32 {
+	if x != nil {
+		return x.Page
+	}
+	return 0
+}
+
+func (x *SearchRoleResponse) GetTotal() int32 {
+	if x != nil {
+		return x.Total
+	}
+	return 0
+}
+
+func (x *SearchRoleResponse) GetList() []*AddRoleRequest {
+	if x != nil {
+		return x.List
+	}
+	return nil
+}
+
+type AddMenuRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id   int64  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *AddMenuRequest) Reset() {
+	*x = AddMenuRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_backend_operation_system_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddMenuRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddMenuRequest) ProtoMessage() {}
+
+func (x *AddMenuRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_backend_operation_system_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddMenuRequest.ProtoReflect.Descriptor instead.
+func (*AddMenuRequest) Descriptor() ([]byte, []int) {
+	return file_backend_operation_system_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *AddMenuRequest) GetId() int64 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *AddMenuRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+// 用户token
+type SystemToken struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
+}
+
+func (x *SystemToken) Reset() {
+	*x = SystemToken{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_backend_operation_system_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SystemToken) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SystemToken) ProtoMessage() {}
+
+func (x *SystemToken) ProtoReflect() protoreflect.Message {
+	mi := &file_backend_operation_system_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SystemToken.ProtoReflect.Descriptor instead.
+func (*SystemToken) Descriptor() ([]byte, []int) {
+	return file_backend_operation_system_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *SystemToken) GetToken() string {
+	if x != nil {
+		return x.Token
+	}
+	return ""
+}
+
+type UserAuth struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserName string `protobuf:"bytes,1,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` // 用户名称
+	Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`                 // 用户密码
+	Phone    string `protobuf:"bytes,3,opt,name=phone,proto3" json:"phone,omitempty"`                       // 用户手机号
+	RoleId   int64  `protobuf:"varint,4,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty"`      // 用户角色id
+	RoleName string `protobuf:"bytes,5,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` // 用户角色名称
+}
+
+func (x *UserAuth) Reset() {
+	*x = UserAuth{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_backend_operation_system_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UserAuth) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UserAuth) ProtoMessage() {}
+
+func (x *UserAuth) ProtoReflect() protoreflect.Message {
+	mi := &file_backend_operation_system_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UserAuth.ProtoReflect.Descriptor instead.
+func (*UserAuth) Descriptor() ([]byte, []int) {
+	return file_backend_operation_system_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *UserAuth) GetUserName() string {
+	if x != nil {
+		return x.UserName
+	}
+	return ""
+}
+
+func (x *UserAuth) GetPassword() string {
+	if x != nil {
+		return x.Password
+	}
+	return ""
+}
+
+func (x *UserAuth) GetPhone() string {
+	if x != nil {
+		return x.Phone
+	}
+	return ""
+}
+
+func (x *UserAuth) GetRoleId() int64 {
+	if x != nil {
+		return x.RoleId
+	}
+	return 0
+}
+
+func (x *UserAuth) GetRoleName() string {
+	if x != nil {
+		return x.RoleName
+	}
+	return ""
+}
+
 var File_backend_operation_system_proto protoreflect.FileDescriptor
 
 var file_backend_operation_system_proto_rawDesc = []byte{
@@ -108,8 +416,36 @@ var file_backend_operation_system_proto_rawDesc = []byte{
 	0x6b, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x04, 0x20,
 	0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70,
 	0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x73, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x06,
-	0x69, 0x73, 0x53, 0x68, 0x6f, 0x77, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x3b, 0x6f, 0x70, 0x65, 0x72,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x69, 0x73, 0x53, 0x68, 0x6f, 0x77, 0x22, 0x58, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
+	0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70,
+	0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12,
+	0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x22, 0x75, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f,
+	0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c,
+	0x12, 0x35, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21,
+	0x2e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x4d, 0x65,
+	0x6e, 0x75, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x23, 0x0a,
+	0x0b, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05,
+	0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b,
+	0x65, 0x6e, 0x22, 0x8f, 0x01, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x12,
+	0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,
+	0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e,
+	0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x17,
+	0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x5f,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65,
+	0x4e, 0x61, 0x6d, 0x65, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x3b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x50, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -124,18 +460,24 @@ func file_backend_operation_system_proto_rawDescGZIP() []byte {
 	return file_backend_operation_system_proto_rawDescData
 }
 
-var file_backend_operation_system_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_backend_operation_system_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
 var file_backend_operation_system_proto_goTypes = []interface{}{
-	(*AddRoleRequest)(nil), // 0: backend.operation.AddRoleRequest
-	(*IsShow)(nil),         // 1: backend.operation.IsShow
+	(*AddRoleRequest)(nil),     // 0: backend.operation.AddRoleRequest
+	(*SearchRoleRequest)(nil),  // 1: backend.operation.SearchRoleRequest
+	(*SearchRoleResponse)(nil), // 2: backend.operation.SearchRoleResponse
+	(*AddMenuRequest)(nil),     // 3: backend.operation.AddMenuRequest
+	(*SystemToken)(nil),        // 4: backend.operation.SystemToken
+	(*UserAuth)(nil),           // 5: backend.operation.UserAuth
+	(*IsShow)(nil),             // 6: backend.operation.IsShow
 }
 var file_backend_operation_system_proto_depIdxs = []int32{
-	1, // 0: backend.operation.AddRoleRequest.is_show:type_name -> backend.operation.IsShow
-	1, // [1:1] is the sub-list for method output_type
-	1, // [1:1] is the sub-list for method input_type
-	1, // [1:1] is the sub-list for extension type_name
-	1, // [1:1] is the sub-list for extension extendee
-	0, // [0:1] is the sub-list for field type_name
+	6, // 0: backend.operation.AddRoleRequest.is_show:type_name -> backend.operation.IsShow
+	0, // 1: backend.operation.SearchRoleResponse.list:type_name -> backend.operation.AddRoleRequest
+	2, // [2:2] is the sub-list for method output_type
+	2, // [2:2] is the sub-list for method input_type
+	2, // [2:2] is the sub-list for extension type_name
+	2, // [2:2] is the sub-list for extension extendee
+	0, // [0:2] is the sub-list for field type_name
 }
 
 func init() { file_backend_operation_system_proto_init() }
@@ -157,6 +499,66 @@ func file_backend_operation_system_proto_init() {
 				return nil
 			}
 		}
+		file_backend_operation_system_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchRoleRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_backend_operation_system_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchRoleResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_backend_operation_system_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddMenuRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_backend_operation_system_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SystemToken); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_backend_operation_system_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UserAuth); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -164,7 +566,7 @@ func file_backend_operation_system_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_backend_operation_system_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   1,
+			NumMessages:   6,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

+ 67 - 0
service/sso/cache.go

@@ -0,0 +1,67 @@
+package sso
+
+import (
+	"encoding/json"
+	"fmt"
+	"kpt-tmr-group/config"
+	"kpt-tmr-group/pkg/tool"
+	operationPb "kpt-tmr-group/proto/go/backend/operation"
+	"time"
+
+	"kpt-tmr-group/pkg/xerr"
+
+	"github.com/go-redis/redis"
+	redisv7 "github.com/go-redis/redis/v7"
+)
+
+type Cache struct {
+	Client *redisv7.Client
+	Expiry time.Duration
+}
+
+func NewCache(cfg *config.AppConfig) *Cache {
+	return &Cache{
+		Client: NewClientLatest(cfg),
+		Expiry: time.Duration(cfg.RedisSetting.SSOCache.Expiry) * time.Minute,
+	}
+}
+
+func (c *Cache) Auth(userAuth *operationPb.UserAuth) (string, error) {
+	return c.get(fmt.Sprintf("sso:auth:%s", tool.Md5String(fmt.Sprintf("%s-%s", userAuth.UserName, userAuth.Password))))
+}
+
+func (c *Cache) CacheAuth(token string, res interface{}) error {
+	return c.set(fmt.Sprintf("sso:auth:%s", token), res)
+}
+
+func (c *Cache) GetAccount(token string) (interface{}, error) {
+	return c.get(fmt.Sprintf("sso:get_account:%s", token))
+}
+
+func (c *Cache) CacheSetAccount(token string, res interface{}) error {
+	return c.set(fmt.Sprintf("sso:get_account:%s", token), res)
+}
+
+func (c *Cache) get(key string) (string, error) {
+	bs, err := c.Client.Get(key).Bytes()
+	if err != nil {
+		return "", xerr.WithMessage(err, key)
+	}
+
+	if len(bs) == 0 {
+		return "", xerr.WithStack(redis.Nil)
+	}
+
+	return string(bs), nil
+}
+
+func (c *Cache) set(key string, res interface{}) error {
+	if res == nil {
+		return nil
+	}
+	b, _ := json.Marshal(res)
+	if err := c.Client.Set(key, string(b), c.Expiry).Err(); err != nil {
+		return xerr.WithMessage(err, key, string(b))
+	}
+	return nil
+}

+ 45 - 0
service/sso/sso.go

@@ -0,0 +1,45 @@
+package sso
+
+import (
+	"kpt-tmr-group/config"
+	"kpt-tmr-group/pkg/di"
+	operationPb "kpt-tmr-group/proto/go/backend/operation"
+
+	redisv7 "github.com/go-redis/redis/v7"
+)
+
+var Module = di.Provide(NewSSOClient)
+
+type ClientInterface interface {
+	Auth(userAuth *operationPb.UserAuth) (string, error)
+	CacheAuth(token string, res interface{}) error
+	CacheSetAccount(token string, res interface{}) error
+	GetAccount(token string) (interface{}, error)
+	// Permissions(token string) (*Response, error)
+	// CheckPermission(token, code string) (bool, error)
+}
+
+func NewClientLatest(cfg *config.AppConfig) *redisv7.Client {
+	return initClientLatest(cfg.RedisSetting.SSOCache.Addr, cfg.RedisSetting.SSOCache.Requirepass, cfg.RedisSetting.SSOCache.DB)
+}
+
+func initClientLatest(addr, password string, db int, opts ...func(*redisv7.Options)) *redisv7.Client {
+	option := &redisv7.Options{
+		Addr:       addr,
+		DB:         db,
+		Password:   password,
+		MaxRetries: 3,
+		OnConnect: func(cn *redisv7.Conn) error {
+			return cn.ClientSetName("on_connect").Err()
+		},
+	}
+	for _, opt := range opts {
+		opt(option)
+	}
+
+	return redisv7.NewClient(option)
+}
+
+func NewSSOClient(cfg *config.AppConfig) ClientInterface {
+	return NewCache(cfg)
+}