🎉 初始化项目,基础功能已完成
This commit is contained in:
commit
174410ffa0
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea
|
||||
vendor
|
||||
logs
|
15
config/alisms.go
Normal file
15
config/alisms.go
Normal file
@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
// 阿里云通讯配置信息
|
||||
type aliSmsConfig struct {
|
||||
AccessKey string
|
||||
AccessSecret string
|
||||
}
|
||||
|
||||
// InitAliSmsConfig 初始化阿里云通信配置
|
||||
func InitAliSmsConfig() {
|
||||
key := getEnvVal("ALI_SMS_KEY", "")
|
||||
secret := getEnvVal("ALI_SMS_SECRET", "")
|
||||
|
||||
AliSmsConfig = aliSmsConfig{AccessKey: key, AccessSecret: secret}
|
||||
}
|
46
config/config.go
Normal file
46
config/config.go
Normal file
@ -0,0 +1,46 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
AliSmsConfig aliSmsConfig
|
||||
RedisConfig redisConfig
|
||||
)
|
||||
|
||||
// 从环境变量获取字符串类型值
|
||||
func getEnvVal(key, defaultVal string) string {
|
||||
val, exist := os.LookupEnv(key)
|
||||
if !exist {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 从环境变量获取数字类型值
|
||||
func getEnvIntVal(key string, defaultVal int) int {
|
||||
valStr, exist := os.LookupEnv(key)
|
||||
if !exist {
|
||||
return defaultVal
|
||||
}
|
||||
val, err := strconv.Atoi(valStr)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 从环境变量获取数字类型值
|
||||
func getEnvBoolVal(key string, defaultVal bool) bool {
|
||||
valStr, exist := os.LookupEnv(key)
|
||||
if !exist {
|
||||
return defaultVal
|
||||
}
|
||||
val, err := strconv.ParseBool(valStr)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
1
config/mysql.go
Normal file
1
config/mysql.go
Normal file
@ -0,0 +1 @@
|
||||
package config
|
28
config/redis.go
Normal file
28
config/redis.go
Normal file
@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
// Redis配置
|
||||
type redisConfig struct {
|
||||
Host string // Redis主机
|
||||
Port string // Redis端口
|
||||
Password string // Redis密码
|
||||
Db int // Redis库
|
||||
}
|
||||
|
||||
// InitRedisConfig 初始化Redis配置
|
||||
func InitRedisConfig() {
|
||||
// RedisHost Redis主机
|
||||
host := getEnvVal("REDIS_HOST", "redis")
|
||||
// RedisPort Redis端口
|
||||
port := getEnvVal("REDIS_PORT", "6379")
|
||||
// RedisPassword Redis密码
|
||||
password := getEnvVal("REDIS_PWD", "")
|
||||
// Redis库
|
||||
db := getEnvIntVal("REDIS_DB", 0)
|
||||
|
||||
RedisConfig = redisConfig{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Password: password,
|
||||
Db: db,
|
||||
}
|
||||
}
|
94
controller/login.go
Normal file
94
controller/login.go
Normal file
@ -0,0 +1,94 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
. "go_api_tmpl/core"
|
||||
. "go_api_tmpl/global"
|
||||
"go_api_tmpl/repository"
|
||||
"go_api_tmpl/utils"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetSmsCodeController 获取登录验证码
|
||||
func GetSmsCodeController(ctx *gin.Context) {
|
||||
type requestBody struct {
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
// 取出并判断设备指纹是否存在
|
||||
deviceId := ctx.GetHeader("di")
|
||||
// 取出手机号
|
||||
var params requestBody
|
||||
err := ctx.ShouldBindJSON(¶ms)
|
||||
if err != nil {
|
||||
Log.Errorf("[发送短信验证码]读取参数错误: %v", err.Error())
|
||||
R(ctx).FailWithMessage("参数错误")
|
||||
return
|
||||
}
|
||||
phone := params.Phone
|
||||
Log.Debugf("设备指纹: %v -----> 手机号: %v", deviceId, phone)
|
||||
// 判断设备是否发送过
|
||||
phoneKey := fmt.Sprintf("auth:sms:phone:%v", phone)
|
||||
flag := RedisConn.ExistKey(phoneKey)
|
||||
if flag {
|
||||
R(ctx).FailWithMessage("发送间隔过短,请稍后重试")
|
||||
return
|
||||
}
|
||||
// 开始发送短信
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
code := fmt.Sprintf("%06v", rnd.Int31n(1000000))
|
||||
// 发送
|
||||
flag = AliSmsBot.SentSms(phone, code)
|
||||
if !flag {
|
||||
R(ctx).FailWithMessage("验证码发送失败,请稍后重试")
|
||||
return
|
||||
}
|
||||
err = RedisConn.SetWithTimeout(phoneKey, code, "600")
|
||||
if err != nil {
|
||||
R(ctx).FailWithMessage("验证码发送失败,请稍后重试")
|
||||
return
|
||||
}
|
||||
R(ctx).OkWithMessage("验证码已发送,有效期十分钟,请尽快使用")
|
||||
}
|
||||
|
||||
// LoginController 登录
|
||||
func LoginController(ctx *gin.Context) {
|
||||
type loginParams struct {
|
||||
Phone string
|
||||
Code string
|
||||
}
|
||||
var params loginParams
|
||||
if err := ctx.ShouldBindJSON(¶ms); err != nil {
|
||||
R(ctx).FailWithMessage("参数错误")
|
||||
return
|
||||
}
|
||||
phoneKey := fmt.Sprintf("auth:sms:phone:%v", params.Phone)
|
||||
if !RedisConn.ExistKey(phoneKey) {
|
||||
R(ctx).FailWithMessageAndCode("未发送验证码或已过期", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
cacheCode, err := RedisConn.GetData(phoneKey)
|
||||
if err != nil {
|
||||
R(ctx).FailWithMessage("系统异常")
|
||||
return
|
||||
}
|
||||
if cacheCode != params.Code {
|
||||
R(ctx).FailWithMessageAndCode("验证码错误", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
// 验证通过,查询数据库数据
|
||||
ur := repository.NewUserRepository()
|
||||
dbUser, err := ur.GetUserByPhone(params.Phone)
|
||||
if err != nil {
|
||||
Log.Errorf("用户数据获取失败: %v", err.Error())
|
||||
R(ctx).FailWithMessage("系统错误")
|
||||
return
|
||||
}
|
||||
token := utils.GenerateToken(dbUser.ID)
|
||||
result := map[string]interface{}{}
|
||||
result["token"] = token
|
||||
|
||||
R(ctx).OkDetailed(result, "登录成功")
|
||||
}
|
22
core/error_handle.go
Normal file
22
core/error_handle.go
Normal file
@ -0,0 +1,22 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// CustomHTTPErrorHandler 默认全局异常处理
|
||||
func CustomHTTPErrorHandler() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
R(ctx).FailWithMessage("不知道出了啥异常")
|
||||
ctx.Abort()
|
||||
}
|
||||
}
|
||||
|
||||
// NotFoundErrorHandler 404异常处理
|
||||
func NotFoundErrorHandler() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
R(ctx).FailWithMessageAndCode("请求接口不存在", http.StatusNotFound)
|
||||
ctx.Abort()
|
||||
}
|
||||
}
|
74
core/response.go
Normal file
74
core/response.go
Normal file
@ -0,0 +1,74 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 返回数据包装
|
||||
type response struct {
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
type rs struct {
|
||||
ctx *gin.Context
|
||||
}
|
||||
|
||||
// 定义状态码
|
||||
const (
|
||||
ERROR = http.StatusInternalServerError
|
||||
SUCCESS = http.StatusOK
|
||||
)
|
||||
|
||||
func R(ctx *gin.Context) *rs {
|
||||
return &rs{ctx: ctx}
|
||||
}
|
||||
|
||||
// Result 手动组装返回结果
|
||||
func (r rs) Result(code int, data interface{}, msg string) {
|
||||
if data == nil {
|
||||
data = map[string]interface{}{}
|
||||
}
|
||||
r.ctx.JSON(code, response{
|
||||
code,
|
||||
data,
|
||||
msg,
|
||||
})
|
||||
}
|
||||
|
||||
// Ok 返回无数据的成功
|
||||
func (r rs) Ok() {
|
||||
r.Result(SUCCESS, nil, "操作成功")
|
||||
}
|
||||
|
||||
// OkWithMessage 返回自定义成功的消息
|
||||
func (r rs) OkWithMessage(message string) {
|
||||
r.Result(SUCCESS, nil, message)
|
||||
}
|
||||
|
||||
// OkWithData 自定义内容的成功返回
|
||||
func (r rs) OkWithData(data interface{}) {
|
||||
r.Result(SUCCESS, data, "操作成功")
|
||||
}
|
||||
|
||||
// OkDetailed 自定义消息和内容的成功返回
|
||||
func (r rs) OkDetailed(data interface{}, message string) {
|
||||
r.Result(SUCCESS, data, message)
|
||||
}
|
||||
|
||||
// Fail 返回默认失败
|
||||
func (r rs) Fail() {
|
||||
r.Result(ERROR, nil, "操作失败")
|
||||
}
|
||||
|
||||
// FailWithMessage 返回默认状态码自定义消息的失败
|
||||
func (r rs) FailWithMessage(message string) {
|
||||
r.Result(ERROR, nil, message)
|
||||
}
|
||||
|
||||
// FailWithMessageAndCode 返回自定义消息和状态码的失败
|
||||
func (r rs) FailWithMessageAndCode(message string, code int) {
|
||||
r.Result(code, nil, message)
|
||||
}
|
28
global/alisms.go
Normal file
28
global/alisms.go
Normal file
@ -0,0 +1,28 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
|
||||
"go_api_tmpl/config"
|
||||
)
|
||||
|
||||
type aliSmsBot struct{}
|
||||
|
||||
// SentSms 发送短信验证码
|
||||
func (b aliSmsBot) SentSms(phone string, code string) bool {
|
||||
client, err := dysmsapi.NewClientWithAccessKey("ap-northeast-1", config.AliSmsConfig.AccessKey, config.AliSmsConfig.AccessSecret)
|
||||
request := dysmsapi.CreateSendSmsRequest()
|
||||
request.Scheme = "https"
|
||||
|
||||
request.PhoneNumbers = phone
|
||||
request.SignName = "悟空单车"
|
||||
request.TemplateCode = "SMS_34310120"
|
||||
request.TemplateParam = fmt.Sprintf("{\"name\":\"%v\",\"code\":\"%v\"}", phone, code)
|
||||
|
||||
response, err := client.SendSms(request)
|
||||
if err != nil {
|
||||
Log.Errorf("验证码发送失败: %v", err.Error())
|
||||
return false
|
||||
}
|
||||
return response.IsSuccess()
|
||||
}
|
8
global/error.go
Normal file
8
global/error.go
Normal file
@ -0,0 +1,8 @@
|
||||
package global
|
||||
|
||||
// CheckError 处理错误
|
||||
func CheckError(err error, msgTmpl string) {
|
||||
if err != nil {
|
||||
Log.Panicf(msgTmpl, err)
|
||||
}
|
||||
}
|
15
global/global.go
Normal file
15
global/global.go
Normal file
@ -0,0 +1,15 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/casbin/casbin/v2"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
MySQLConn *gorm.DB
|
||||
RedisConn RedisClient
|
||||
AliSmsBot aliSmsBot
|
||||
Enforcer *casbin.Enforcer
|
||||
Log *zap.SugaredLogger
|
||||
)
|
32
global/logger.go
Normal file
32
global/logger.go
Normal file
@ -0,0 +1,32 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InitLogger 初始化日志工具
|
||||
func InitLogger() {
|
||||
// 配置 sugaredLogger
|
||||
writer := zapcore.AddSync(os.Stdout)
|
||||
|
||||
// 自定义时间输出格式
|
||||
customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
enc.AppendString("[" + t.Format("2006-01-02 15:04:05.000") + "]")
|
||||
}
|
||||
|
||||
// 格式相关的配置
|
||||
encoderConfig := zap.NewProductionEncoderConfig()
|
||||
// 修改时间戳的格式
|
||||
encoderConfig.EncodeTime = customTimeEncoder
|
||||
// 日志级别使用大写带颜色显示
|
||||
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
encoder := zapcore.NewConsoleEncoder(encoderConfig)
|
||||
// 将日志级别设置为 DEBUG
|
||||
core := zapcore.NewCore(encoder, writer, zapcore.DebugLevel)
|
||||
// 增加 caller 信息
|
||||
logger := zap.New(core, zap.AddCaller())
|
||||
Log = logger.Sugar()
|
||||
}
|
36
global/mysql.go
Normal file
36
global/mysql.go
Normal file
@ -0,0 +1,36 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InitMySQLClient 初始化MySQL连接
|
||||
func InitMySQLClient() {
|
||||
USER := "casbin"
|
||||
PASS := "casbin123"
|
||||
HOST := "192.168.3.9"
|
||||
PORT := "3306"
|
||||
DBNAME := "casbin_demo"
|
||||
|
||||
newLogger := logger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Info, // Log level
|
||||
Colorful: true, // Disable color
|
||||
},
|
||||
)
|
||||
|
||||
url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", USER, PASS, HOST, PORT, DBNAME)
|
||||
conn, err := gorm.Open(mysql.Open(url), &gorm.Config{Logger: newLogger})
|
||||
if err != nil {
|
||||
Log.Panicf("初始化MySQL连接失败, 错误信息: %v", err)
|
||||
}
|
||||
MySQLConn = conn
|
||||
}
|
57
global/redis.go
Normal file
57
global/redis.go
Normal file
@ -0,0 +1,57 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
// RedisClient Redis连接对象
|
||||
type RedisClient struct {
|
||||
Client redis.Conn
|
||||
}
|
||||
|
||||
// GetData 获取数据
|
||||
func (r *RedisClient) GetData(key string) (string, error) {
|
||||
return redis.String(r.Client.Do("get", key))
|
||||
}
|
||||
|
||||
// GetKeys 获取key列表
|
||||
func (r *RedisClient) GetKeys(key string) ([]string, error) {
|
||||
return redis.Strings(r.Client.Do("keys", key))
|
||||
}
|
||||
|
||||
// ExistKey 判断是否存在key
|
||||
func (r *RedisClient) ExistKey(key string) bool {
|
||||
keys, err := redis.Strings(r.Client.Do("keys", key))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return len(keys) > 0
|
||||
}
|
||||
|
||||
// Set 保存数据
|
||||
func (r *RedisClient) Set(key string, value string) error {
|
||||
_, err := r.Client.Do("set", key, value)
|
||||
if err != nil {
|
||||
return errors.New("Redis保存数据失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWithTimeout 保存带过期时间的数据(单位:秒)
|
||||
func (r *RedisClient) SetWithTimeout(key string, value string, timeout string) error {
|
||||
_, err := r.Client.Do("set", key, value, "EX", timeout)
|
||||
if err != nil {
|
||||
return errors.New("Redis保存数据失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Del 根据key删除Redis数据
|
||||
func (r *RedisClient) Del(key string) error {
|
||||
_, err := r.Client.Do("DEL", key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
16
go.mod
Normal file
16
go.mod
Normal file
@ -0,0 +1,16 @@
|
||||
module go_api_tmpl
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1238
|
||||
github.com/casbin/casbin/v2 v2.28.3
|
||||
github.com/casbin/gorm-adapter/v3 v3.3.3
|
||||
github.com/garyburd/redigo v1.6.2
|
||||
github.com/gin-gonic/gin v1.7.4
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
go.uber.org/zap v1.19.0
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
gorm.io/driver/mysql v1.1.2
|
||||
gorm.io/gorm v1.21.13
|
||||
)
|
277
go.sum
Normal file
277
go.sum
Normal file
@ -0,0 +1,277 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1238 h1:K0l7Nb8xi2nb/j6evXwGofebgW+6XT/AuVOEuWGI344=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1238/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/casbin/casbin/v2 v2.28.3 h1:iHxxEsNHwSciRoYh+54etVUA8AXKS9OKzNy6/39UWvY=
|
||||
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||
github.com/casbin/gorm-adapter/v3 v3.3.3 h1:aO3ixIs+FsGh/in+iXXY8rLpdmeucs+s50T/RI2Rsdc=
|
||||
github.com/casbin/gorm-adapter/v3 v3.3.3/go.mod h1:z0J/CpAznL6MyXMPnzltbLBI6lykprGc1rusy+vMJps=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
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/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
|
||||
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
|
||||
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.8.0 h1:FmjZ0rOyXTr1wfWs45i4a9vjnjWUAGpMuQLD9OSs+lw=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||
github.com/jackc/pgtype v1.6.2 h1:b3pDeuhbbzBYcg5kwNmNDun4pFUD/0AAr1kLXZLeNt8=
|
||||
github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||
github.com/jackc/pgx/v4 v4.10.1 h1:/6Q3ye4myIj6AaplUm+eRcz4OhK9HAvFf4ePsG40LJY=
|
||||
github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
|
||||
gorm.io/driver/mysql v1.1.2 h1:OofcyE2lga734MxwcCW9uB4mWNXMr50uaGRVwQL2B0M=
|
||||
gorm.io/driver/mysql v1.1.2/go.mod h1:4P/X9vSc3WTrhTLZ259cpFd6xKNYiSSdSZngkSBGIMM=
|
||||
gorm.io/driver/postgres v1.0.8 h1:PAgM+PaHOSAeroTjHkCHCBIHHoBIf9RgPWGo8dF2DA8=
|
||||
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
|
||||
gorm.io/driver/sqlserver v1.0.4 h1:V15fszi0XAo7fbx3/cF50ngshDSN4QT0MXpWTylyPTY=
|
||||
gorm.io/driver/sqlserver v1.0.4/go.mod h1:ciEo5btfITTBCj9BkoUVDvgQbUdLWQNqdFY5OGuGnRg=
|
||||
gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/gorm v1.21.13 h1:JU5A4yVemRjdMndJ0oZU7VX+Nr2ICE3C60U5bgR6mHE=
|
||||
gorm.io/gorm v1.21.13/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||
gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00=
|
||||
gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
14
handle/apis.go
Normal file
14
handle/apis.go
Normal file
@ -0,0 +1,14 @@
|
||||
package handle
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/repository"
|
||||
)
|
||||
|
||||
// SaveAllRoute 保存入库所有接口路由信息
|
||||
func SaveAllRoute(routes gin.RoutesInfo) {
|
||||
global.Log.Debugf("待入库路由数量: %v", len(routes))
|
||||
ar := repository.NewApisRepository()
|
||||
ar.SaveAllApi(routes)
|
||||
}
|
1
handle/request_log.go
Normal file
1
handle/request_log.go
Normal file
@ -0,0 +1 @@
|
||||
package handle
|
33
initialization/casbin.go
Normal file
33
initialization/casbin.go
Normal file
@ -0,0 +1,33 @@
|
||||
package initialization
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
gormAdapter "github.com/casbin/gorm-adapter/v3"
|
||||
"go_api_tmpl/global"
|
||||
)
|
||||
|
||||
// Casbin 初始化Casbin的RABC模型
|
||||
func Casbin() {
|
||||
// Initialize casbin adapter
|
||||
adapter, err := gormAdapter.NewAdapterByDBUseTableName(global.MySQLConn, "", "t_role_rule")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to initialize casbin adapter: %v", err))
|
||||
}
|
||||
|
||||
// 初始化模型
|
||||
model := model.NewModel()
|
||||
model.AddDef("r", "r", "sub, obj, act")
|
||||
model.AddDef("p", "p", "sub, obj, act")
|
||||
model.AddDef("g", "g", "_, _")
|
||||
model.AddDef("e", "e", "some(where (p.eft == allow))")
|
||||
// 匹配规则(下面的规则适用与根据Gin的Route的Path和Method做校验,最后那个r.sub == 1是用来判断超级管理员的)
|
||||
model.AddDef("m", "m", "g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act) || r.sub == \"1\"")
|
||||
|
||||
enf, err := casbin.NewEnforcer(model, adapter)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to create casbin enforcer: %v", err))
|
||||
}
|
||||
global.Enforcer = enf
|
||||
}
|
48
initialization/db.go
Normal file
48
initialization/db.go
Normal file
@ -0,0 +1,48 @@
|
||||
package initialization
|
||||
|
||||
import (
|
||||
. "go_api_tmpl/global"
|
||||
"go_api_tmpl/repository"
|
||||
)
|
||||
|
||||
// DatabaseTable 初始化数据库表结构
|
||||
func DatabaseTable() {
|
||||
// 初始化菜单表
|
||||
Log.Debug("开始初始化接口路由表")
|
||||
ar := repository.NewApisRepository()
|
||||
err := ar.Migrate()
|
||||
CheckError(err, "接口路由表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化用户表")
|
||||
ur := repository.NewUserRepository()
|
||||
err = ur.Migrate()
|
||||
CheckError(err, "用户表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化角色表")
|
||||
rr := repository.NewRoleRepository()
|
||||
err = rr.Migrate()
|
||||
CheckError(err, "角色表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化菜单表")
|
||||
mr := repository.NewMenuRepository()
|
||||
err = mr.Migrate()
|
||||
CheckError(err, "菜单表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化用户角色表")
|
||||
urr := repository.NewUserRoleRepository()
|
||||
err = urr.Migrate()
|
||||
CheckError(err, "用户角色表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化角色菜单表")
|
||||
rmr := repository.NewRoleMenuRepository()
|
||||
err = rmr.Migrate()
|
||||
CheckError(err, "角色菜单表初始化失败: %v")
|
||||
|
||||
Log.Debug("开始初始化接口访问记录表")
|
||||
rlr := repository.NewRequestLogRepository()
|
||||
err = rlr.Migrate()
|
||||
CheckError(err, "接口访问记录表初始化失败: %v")
|
||||
|
||||
// TODO 初始化其他表
|
||||
Log.Debug("所有数据库表初始化完成")
|
||||
}
|
14
initialization/init.go
Normal file
14
initialization/init.go
Normal file
@ -0,0 +1,14 @@
|
||||
package initialization
|
||||
|
||||
import "go_api_tmpl/config"
|
||||
|
||||
func Init() {
|
||||
// 初始化数据库表
|
||||
DatabaseTable()
|
||||
// 初始化Casbin
|
||||
Casbin()
|
||||
// 初始化Redis
|
||||
InitRedisConn()
|
||||
// 阿里云短信配置
|
||||
config.InitAliSmsConfig()
|
||||
}
|
35
initialization/redis.go
Normal file
35
initialization/redis.go
Normal file
@ -0,0 +1,35 @@
|
||||
package initialization
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/garyburd/redigo/redis"
|
||||
"go_api_tmpl/config"
|
||||
"go_api_tmpl/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InitRedisConn 初始化Redis连接对象
|
||||
func InitRedisConn() {
|
||||
// 读取配置
|
||||
config.InitRedisConfig()
|
||||
// 初始化连接
|
||||
conn, err := redis.Dial("tcp",
|
||||
// Redis连接信息
|
||||
fmt.Sprintf("%s:%s", config.RedisConfig.Host, config.RedisConfig.Port),
|
||||
// 密码
|
||||
redis.DialPassword(config.RedisConfig.Password),
|
||||
// 默认使用数据库
|
||||
redis.DialDatabase(config.RedisConfig.Db),
|
||||
redis.DialKeepAlive(1*time.Second),
|
||||
redis.DialConnectTimeout(5*time.Second),
|
||||
redis.DialReadTimeout(1*time.Second),
|
||||
redis.DialWriteTimeout(1*time.Second))
|
||||
if err != nil {
|
||||
global.Log.Panicf("Redis初始化连接失败: %v", err.Error())
|
||||
} else {
|
||||
global.Log.Info("Redis连接初始化成功")
|
||||
global.RedisConn = global.RedisClient{
|
||||
Client: conn,
|
||||
}
|
||||
}
|
||||
}
|
36
main.go
Normal file
36
main.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/core"
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/handle"
|
||||
"go_api_tmpl/initialization"
|
||||
"go_api_tmpl/middleware"
|
||||
"go_api_tmpl/route"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 初始化日志工具
|
||||
global.InitLogger()
|
||||
// 初始化数据库连接
|
||||
global.InitMySQLClient()
|
||||
// 初始化相关组件
|
||||
initialization.Init()
|
||||
|
||||
// 初始化Gin
|
||||
//app := gin.New()
|
||||
//app.Use(middleware.ZapLogger(), gin.Recovery())
|
||||
app := gin.Default()
|
||||
// 定义全局异常处理
|
||||
app.NoRoute(core.NotFoundErrorHandler())
|
||||
// 保存接口访问记录
|
||||
app.Use(middleware.SaveRequestLog(), middleware.CheckDeviceId())
|
||||
// 初始化路由
|
||||
route.InitRoute(app)
|
||||
// 路由初始化完毕,入库所有接口
|
||||
handle.SaveAllRoute(app.Routes())
|
||||
|
||||
// 启动项目
|
||||
_ = app.Run(":8888")
|
||||
}
|
47
middleware/casbin.go
Normal file
47
middleware/casbin.go
Normal file
@ -0,0 +1,47 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/core"
|
||||
. "go_api_tmpl/global"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// AuthorityVerify 权限验证中间件
|
||||
func AuthorityVerify() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 取出用户ID
|
||||
userId, existed := c.Get("userId")
|
||||
if !existed {
|
||||
core.R(c).FailWithMessageAndCode("请先登录", http.StatusUnauthorized)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
Log.Info(userId)
|
||||
// 从数据库加载权限规则数据
|
||||
err := Enforcer.LoadPolicy()
|
||||
if err != nil {
|
||||
core.R(c).FailWithMessage("权限加载失败")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 取出Path和Method
|
||||
p := c.Request.URL.Path
|
||||
m := c.Request.Method
|
||||
// 验证权限
|
||||
ok, err := Enforcer.Enforce(fmt.Sprint(userId), p, m)
|
||||
if err != nil {
|
||||
core.R(c).FailWithMessage("权限验证失败")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
core.R(c).FailWithMessage("权限不足")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
41
middleware/jwt.go
Normal file
41
middleware/jwt.go
Normal file
@ -0,0 +1,41 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"go_api_tmpl/core"
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// AuthorizeJWT 验证JWT
|
||||
func AuthorizeJWT() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
const BearerSchema string = "Bearer "
|
||||
authHeader := ctx.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
core.R(ctx).FailWithMessageAndCode("请先登录", http.StatusUnauthorized)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
tokenString := authHeader[len(BearerSchema):]
|
||||
|
||||
if token, err := utils.ValidateToken(tokenString); err != nil {
|
||||
global.Log.Errorf("Token校验失败: %v ------> %v", tokenString, err.Error())
|
||||
core.R(ctx).FailWithMessageAndCode("Token校验失败", http.StatusUnauthorized)
|
||||
return
|
||||
} else {
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); !ok {
|
||||
ctx.AbortWithStatus(http.StatusUnauthorized)
|
||||
} else {
|
||||
if token.Valid {
|
||||
ctx.Set("userId", claims["userId"])
|
||||
} else {
|
||||
ctx.AbortWithStatus(http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
39
middleware/logger.go
Normal file
39
middleware/logger.go
Normal file
@ -0,0 +1,39 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/global"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ZapLogger 接收gin框架的路由日志
|
||||
func ZapLogger() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
query := c.Request.URL.RawQuery
|
||||
c.Next()
|
||||
|
||||
cost := time.Since(start)
|
||||
//global.Log.Info(path,
|
||||
// zap.Int("status", c.Writer.Status()),
|
||||
// zap.String("method", c.Request.Method),
|
||||
// zap.String("path", path),
|
||||
// zap.String("query", query),
|
||||
// zap.String("ip", c.ClientIP()),
|
||||
// zap.String("user-agent", c.Request.UserAgent()),
|
||||
// zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
|
||||
// zap.Duration("cost", cost),
|
||||
//)
|
||||
logTmpl := `
|
||||
=================================================================================
|
||||
Path: %v
|
||||
Param: %v
|
||||
Method: %v
|
||||
IP: %v
|
||||
Cost: %v
|
||||
=================================================================================
|
||||
`
|
||||
global.Log.Debugf(logTmpl, path, query, c.Request.Method, c.ClientIP(), cost)
|
||||
}
|
||||
}
|
76
middleware/request.go
Normal file
76
middleware/request.go
Normal file
@ -0,0 +1,76 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/core"
|
||||
"go_api_tmpl/model"
|
||||
"go_api_tmpl/repository"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CheckDeviceId 检查是否存在设备指纹
|
||||
func CheckDeviceId() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
// 取出设备指纹
|
||||
deviceId := ctx.Request.Header.Get("di")
|
||||
if deviceId == "" {
|
||||
// 设备指纹不存在
|
||||
core.R(ctx).FailWithMessageAndCode("请求不合法", http.StatusBadRequest)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// SaveRequestLog 保存所有请求接口日志
|
||||
func SaveRequestLog() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
// 开始时间
|
||||
start := time.Now()
|
||||
// 取出接口
|
||||
path := ctx.Request.URL.Path
|
||||
// 取出参数
|
||||
query := ctx.Request.URL.RawQuery
|
||||
// body参数
|
||||
body, err := ctx.GetRawData()
|
||||
bodyStr := ""
|
||||
if err == nil {
|
||||
bodyStr = string(body)
|
||||
ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
||||
}
|
||||
// form参数
|
||||
form := ctx.Request.Form.Encode()
|
||||
// 取出请求方式
|
||||
method := ctx.Request.Method
|
||||
// 取出设备指纹
|
||||
deviceId := ctx.Request.Header.Get("di")
|
||||
// 取出IP
|
||||
ip := ctx.ClientIP()
|
||||
// UA
|
||||
ua := ctx.Request.UserAgent()
|
||||
ctx.Next()
|
||||
// 计算耗时
|
||||
cost := time.Since(start).Milliseconds()
|
||||
// 组装实体
|
||||
rlog := model.RequestLog{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Param: query,
|
||||
Body: bodyStr,
|
||||
Form: form,
|
||||
Cost: cost,
|
||||
StatusCode: ctx.Writer.Status(),
|
||||
DeviceId: deviceId,
|
||||
Ip: ip,
|
||||
UserAgent: ua,
|
||||
}
|
||||
|
||||
//global.Log.Debugf("接口请求结果: %v", rlog)
|
||||
rlr := repository.NewRequestLogRepository()
|
||||
rlr.SaveLog(&rlog)
|
||||
}
|
||||
}
|
11
model/apis.go
Normal file
11
model/apis.go
Normal file
@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
type Apis struct {
|
||||
ID uint `json:"id" gorm:"primarykey"`
|
||||
Path string `json:"path" `
|
||||
Method string `json:"method" `
|
||||
}
|
||||
|
||||
func (Apis) TableName() string {
|
||||
return "t_api_route"
|
||||
}
|
11
model/menu.go
Normal file
11
model/menu.go
Normal file
@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Menu struct {
|
||||
gorm.Model
|
||||
}
|
||||
|
||||
func (Menu) TableName() string {
|
||||
return "t_menu"
|
||||
}
|
25
model/request_log.go
Normal file
25
model/request_log.go
Normal file
@ -0,0 +1,25 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RequestLog 请求日志实体
|
||||
type RequestLog struct {
|
||||
ID uint `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
Method string `json:"method" gorm:"type:varchar(10) not null comment '请求方式';"` // 请求方式
|
||||
Path string `json:"path" gorm:"type:varchar(100) not null comment '请求接口';"` // 请求接口
|
||||
Param string `json:"param" gorm:"type:text comment 'Query参数';"` // Query参数
|
||||
Body string `json:"body" gorm:"type:text comment 'Body参数';"` // Body参数
|
||||
Form string `json:"form" gorm:"type:text comment 'Form参数';"` // Form参数
|
||||
Cost int64 `json:"cost" gorm:"type:int comment 'Query参数';"` // 耗时(微秒)
|
||||
StatusCode int `json:"status_code" gorm:"type:int comment '返回状态码';"` // 返回状态码
|
||||
DeviceId string `json:"device_id" gorm:"type:varchar(50) not null comment '设备指纹';"` // 设备指纹
|
||||
Ip string `json:"ip" gorm:"type:varchar(50) comment 'IP地址';"` // IP地址
|
||||
UserAgent string `json:"user_agent" gorm:"type:varchar(500) comment 'UserAgent';"` // UA
|
||||
}
|
||||
|
||||
func (RequestLog) TableName() string {
|
||||
return "t_request_log"
|
||||
}
|
11
model/role.go
Normal file
11
model/role.go
Normal file
@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Role struct {
|
||||
gorm.Model
|
||||
}
|
||||
|
||||
func (Role) TableName() string {
|
||||
return "t_role"
|
||||
}
|
11
model/role_menu.go
Normal file
11
model/role_menu.go
Normal file
@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type RoleMenu struct {
|
||||
gorm.Model
|
||||
}
|
||||
|
||||
func (RoleMenu) TableName() string {
|
||||
return "t_role_menu"
|
||||
}
|
12
model/user.go
Normal file
12
model/user.go
Normal file
@ -0,0 +1,12 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Phone string
|
||||
}
|
||||
|
||||
func (User) TableName() string {
|
||||
return "t_user"
|
||||
}
|
11
model/user_role.go
Normal file
11
model/user_role.go
Normal file
@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type UserRole struct {
|
||||
gorm.Model
|
||||
}
|
||||
|
||||
func (UserRole) TableName() string {
|
||||
return "t_user_role"
|
||||
}
|
35
repository/apis_repository.go
Normal file
35
repository/apis_repository.go
Normal file
@ -0,0 +1,35 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
. "go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type apisRepository struct{}
|
||||
|
||||
type ApisRepository interface {
|
||||
SaveAllApi(info gin.RoutesInfo)
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewApisRepository 新建实例
|
||||
func NewApisRepository() ApisRepository {
|
||||
return apisRepository{}
|
||||
}
|
||||
|
||||
// SaveAllApi 保存所有gin的路由
|
||||
func (ar apisRepository) SaveAllApi(routes gin.RoutesInfo) {
|
||||
for _, route := range routes {
|
||||
m := model.Apis{Path: route.Path, Method: route.Method}
|
||||
err := MySQLConn.FirstOrCreate(&m, &m).Error
|
||||
if err != nil {
|
||||
Log.Infof("保存菜单错误: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (ar apisRepository) Migrate() error {
|
||||
return MySQLConn.AutoMigrate(&model.Apis{})
|
||||
}
|
22
repository/menu_repository.go
Normal file
22
repository/menu_repository.go
Normal file
@ -0,0 +1,22 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type menuRepository struct{}
|
||||
|
||||
type MenuRepository interface {
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewMenuRepository 新建实例
|
||||
func NewMenuRepository() MenuRepository {
|
||||
return menuRepository{}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r menuRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.Menu{})
|
||||
}
|
30
repository/request_log_repository.go
Normal file
30
repository/request_log_repository.go
Normal file
@ -0,0 +1,30 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type requestLogRepository struct{}
|
||||
|
||||
type RequestLogRepository interface {
|
||||
SaveLog(log *model.RequestLog)
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewRequestLogRepository 新建实例
|
||||
func NewRequestLogRepository() RequestLogRepository {
|
||||
return requestLogRepository{}
|
||||
}
|
||||
|
||||
// SaveLog 保存接口访问记录
|
||||
func (r requestLogRepository) SaveLog(log *model.RequestLog) {
|
||||
if err := global.MySQLConn.Create(log).Error; err != nil {
|
||||
global.Log.Errorf("接口访问记录保存错误: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r requestLogRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.RequestLog{})
|
||||
}
|
22
repository/role_menu_repository.go
Normal file
22
repository/role_menu_repository.go
Normal file
@ -0,0 +1,22 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type roleMenuRepository struct{}
|
||||
|
||||
type RoleMenuRepository interface {
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewRoleMenuRepository 新建实例
|
||||
func NewRoleMenuRepository() RoleMenuRepository {
|
||||
return roleMenuRepository{}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r roleMenuRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.RoleMenu{})
|
||||
}
|
22
repository/role_repository.go
Normal file
22
repository/role_repository.go
Normal file
@ -0,0 +1,22 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type roleRepository struct{}
|
||||
|
||||
type RoleRepository interface {
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewRoleRepository 新建实例
|
||||
func NewRoleRepository() RoleRepository {
|
||||
return roleRepository{}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r roleRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.Role{})
|
||||
}
|
33
repository/user_repository.go
Normal file
33
repository/user_repository.go
Normal file
@ -0,0 +1,33 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type userRepository struct{}
|
||||
|
||||
type UserRepository interface {
|
||||
Migrate() error
|
||||
GetUserByPhone(string) (*model.User, error)
|
||||
}
|
||||
|
||||
// NewUserRepository 新建实例
|
||||
func NewUserRepository() UserRepository {
|
||||
return userRepository{}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r userRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.User{})
|
||||
}
|
||||
|
||||
// GetUserByPhone 根据手机号查询用户信息
|
||||
func (r userRepository) GetUserByPhone(phone string) (*model.User, error) {
|
||||
u := model.User{Phone: phone}
|
||||
err := global.MySQLConn.FirstOrCreate(&u, &u).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &u, nil
|
||||
}
|
22
repository/user_role_repository.go
Normal file
22
repository/user_role_repository.go
Normal file
@ -0,0 +1,22 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"go_api_tmpl/global"
|
||||
"go_api_tmpl/model"
|
||||
)
|
||||
|
||||
type userRoleRepository struct{}
|
||||
|
||||
type UserRoleRepository interface {
|
||||
Migrate() error
|
||||
}
|
||||
|
||||
// NewUserRoleRepository 新建实例
|
||||
func NewUserRoleRepository() UserRoleRepository {
|
||||
return userRoleRepository{}
|
||||
}
|
||||
|
||||
// Migrate 初始化数据库结构
|
||||
func (r userRoleRepository) Migrate() error {
|
||||
return global.MySQLConn.AutoMigrate(&model.UserRole{})
|
||||
}
|
14
route/login.go
Normal file
14
route/login.go
Normal file
@ -0,0 +1,14 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/controller"
|
||||
)
|
||||
|
||||
// 初始化登录相关接口路由
|
||||
func initLoginRoute(r *gin.RouterGroup) {
|
||||
// 获取短信验证码
|
||||
r.POST("/sms", controller.GetSmsCodeController)
|
||||
// 登录
|
||||
r.POST("/login", controller.LoginController)
|
||||
}
|
17
route/route.go
Normal file
17
route/route.go
Normal file
@ -0,0 +1,17 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/core"
|
||||
)
|
||||
|
||||
func InitRoute(app *gin.Engine) {
|
||||
app.GET("/", func(context *gin.Context) {
|
||||
core.R(context).OkWithMessage("瞅啥呢?")
|
||||
})
|
||||
group := app.Group("/api")
|
||||
// 登录相关接口路由
|
||||
initLoginRoute(group)
|
||||
// 测试用的
|
||||
initTestRoute(group)
|
||||
}
|
19
route/test.go
Normal file
19
route/test.go
Normal file
@ -0,0 +1,19 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go_api_tmpl/core"
|
||||
"go_api_tmpl/middleware"
|
||||
)
|
||||
|
||||
func initTestRoute(r *gin.RouterGroup) {
|
||||
group := r.Group("/test", middleware.AuthorizeJWT())
|
||||
|
||||
group.GET("/pub", func(context *gin.Context) {
|
||||
core.R(context).OkWithMessage("已登录且无需权限可访问")
|
||||
})
|
||||
|
||||
group.GET("/hello", middleware.AuthorityVerify(), func(context *gin.Context) {
|
||||
core.R(context).OkWithMessage("已登录且有权限")
|
||||
})
|
||||
}
|
49
utils/bcrypt.go
Normal file
49
utils/bcrypt.go
Normal file
@ -0,0 +1,49 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func HashPassword(pass *string) {
|
||||
bytePass := []byte(*pass)
|
||||
hPass, _ := bcrypt.GenerateFromPassword(bytePass, bcrypt.DefaultCost)
|
||||
*pass = string(hPass)
|
||||
}
|
||||
|
||||
func ComparePassword(dbPass, pass string) bool {
|
||||
return bcrypt.CompareHashAndPassword([]byte(dbPass), []byte(pass)) == nil
|
||||
}
|
||||
|
||||
//GenerateToken -> generates token
|
||||
func GenerateToken(userId uint) string {
|
||||
claims := jwt.MapClaims{
|
||||
"exp": time.Now().Add(time.Hour * 3).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
"userId": userId,
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
t, _ := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
|
||||
// 保存Token到Redis
|
||||
//redisKey := fmt.Sprintf("auth:token:%v", userId)
|
||||
//_ = global.RedisConn.SetWithTimeout(redisKey, t, "10800")
|
||||
return t
|
||||
|
||||
}
|
||||
|
||||
//ValidateToken --> validate the given token
|
||||
func ValidateToken(token string) (*jwt.Token, error) {
|
||||
|
||||
//2nd arg function return secret key after checking if the signing method is HMAC and returned key is used by 'Parse' to decode the token)
|
||||
return jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
//nil secret key
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(os.Getenv("JWT_SECRET")), nil
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user