Commits (9)
# IDE
.idea/
.vscode/
# BUILD
build/
*.exe
*.so
*.dll
# DOCS & CONFIG
docs/
conf.yaml
# SECRET
*.pem
# LOGS
*.log
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>
package controller
import (
"go-svc-tpl/utils"
"net/http"
"time"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
)
// set token into cookie
func setToken(c echo.Context, token string) {
cookie := new(http.Cookie)
cookie.Name = "token"
cookie.Value = token
cookie.Expires = time.Now().Add(24 * time.Hour)
cookie.Path = "/" // set the path, or it will be /user
c.SetCookie(cookie)
logrus.Info("set token " + token)
}
// get token from cookie
// return "" if not found
func GetToken(c echo.Context) string {
cookie, _ := c.Cookie("token") // 没有错误处理(?)
if cookie == nil {
return ""
}
return cookie.Value
}
// get the username by token
// return username "default" if no user is found
func getName(c echo.Context) string {
token := GetToken(c)
if token == "" {
return "default"
}
claims, _ := utils.ParseToken(token)
if claims == nil {
return "default"
}
return claims.Username
}
package controller
import (
"go-svc-tpl/app/response"
"go-svc-tpl/model"
"go-svc-tpl/utils"
"strconv"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
)
func Register(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email")
pwd := c.FormValue("pwd")
// !!! without validation now
err := model.RegisterUser(name, email, pwd)
if err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "register failed", "")
}
return response.SendResponse(c, 0, "register successfully", "")
}
// get token from (email, pwd)
func Login(c echo.Context) error {
email := c.FormValue("email")
pwd := c.FormValue("pwd")
var msg string
var code int
// !!! without validation now
// judge whether the user exists
exist := model.CheckAuth(email, pwd)
if exist {
token, err := utils.GenToken(email, pwd)
if err != nil {
code = 1
msg = "can't generate token"
logrus.Error(err)
} else {
code = 0
msg = "generate token successfully"
setToken(c, token)
}
} else {
code = 1
msg = "user not exist"
}
return response.SendResponse(c, code, msg, "")
}
// by frontend ?
func Logout(c echo.Context) error {
return nil
}
func Info(c echo.Context) error {
name := getName(c)
user, err := model.GetUser(name)
if err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "get user failed", "")
}
data := struct {
Name string `json:"name"`
Email string `json:"Email"`
}{name, user.Email}
return response.SendResponse(c, 0, "get info successfully", data)
}
func GetRecord(c echo.Context) error {
name := getName(c)
data, err := model.GetRecord(name)
if err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "get failed", "")
}
return response.SendResponse(c, 0, "get record successfully", data)
}
func GetUrl(c echo.Context) error {
name := getName(c)
data, err := model.GetUrl(name)
if err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "get failed", "")
}
return response.SendResponse(c, 0, "get url successfully", data)
}
func Create(c echo.Context) error {
// get data of shortlink from request
var link model.ShortLink
if err := c.Bind(&link); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "request error", "")
}
if link.Short == "" {
link.Short = utils.GenShort()
}
// create a new link to user by name
name := getName(c)
var id int
var err error
if id, err = model.CreateLink(name, link); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "create failed", "")
}
return response.SendResponse(c, 0, "create successfully", struct {
ID int `json:"id"`
}{id})
}
func Query(c echo.Context) error {
name := getName(c)
id, _ := strconv.Atoi(c.FormValue("id"))
var link model.ShortLink
var err error
if link, err = model.QueryLink(name, id); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "query error", "")
}
return response.SendResponse(c, 0, "query successfully", link)
}
func Update(c echo.Context) error {
// read update data
var data model.UpdateData
if err := c.Bind(&data); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "request error", "")
}
// update the data of user
name := getName(c)
if err := model.UpdateLink(name, data); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "update error", "")
}
return response.SendResponse(c, 0, "update successfully", "")
}
func Delete(c echo.Context) error {
name := getName(c)
id, _ := strconv.Atoi(c.FormValue("id"))
if err := model.DeleteLink(name, id); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "delete error", "")
}
return response.SendResponse(c, 0, "delete successfully", "")
}
func Pause(c echo.Context) error {
name := getName(c)
id, _ := strconv.Atoi(c.FormValue("id"))
if err := model.PauseLink(name, id); err != nil {
logrus.Error(err)
return response.SendResponse(c, 1, "puase error", "")
}
return response.SendResponse(c, 0, "pause succesfully", "")
}
package app
import (
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
)
var e *echo.Echo
func InitWebFramework() {
e = echo.New()
e.HideBanner = true
addRoutes()
logrus.Info("echo framework initialized")
}
func StartServer() {
e.Logger.Fatal(e.Start(":1926"))
}
package midware
import (
"go-svc-tpl/app/controller"
"go-svc-tpl/app/response"
"go-svc-tpl/utils"
"net/http"
"time"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
)
// validate token
func Auth(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
token := controller.GetToken(c)
var code int
var msg string
if token == "" {
code = 0 // no login but can use
logrus.Info("not login yet")
} else {
claims, err := utils.ParseToken(token)
if err != nil {
code = 1
msg = "token check fail"
logrus.Error(err)
} else if time.Now().Unix() > claims.ExpiresAt {
code = 1
msg = "token expired"
} else {
code = 0
}
}
// if not success, abort the program
if code != 0 {
response.SendResponse(c, code, msg, "")
return echo.NewHTTPError(http.StatusUnauthorized, msg)
}
// check pass, continue
return next(c)
}
}
package response
import (
"net/http"
"github.com/labstack/echo/v4"
)
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
func SendResponse(c echo.Context, code int, msg string, data ...interface{}) error {
return c.JSON(http.StatusOK, Response{
Code: code,
Msg: msg,
Data: data,
})
}
package app
import (
"go-svc-tpl/app/controller"
"go-svc-tpl/app/midware"
"go-svc-tpl/app/response"
"github.com/labstack/echo/v4"
echoSwagger "github.com/swaggo/echo-swagger"
)
func ping(c echo.Context) error {
return response.SendResponse(c, 0, "ok", "Pong!")
}
func addRoutes() {
api := e.Group("api")
api.GET("/doc/*", echoSwagger.WrapHandler)
api.GET("/ping", ping)
user := e.Group("user")
user.POST("/register", controller.Register)
user.Use(midware.Auth)
user.POST("/login", controller.Login)
user.POST("/logout", controller.Logout)
user.POST("/info", controller.Info, midware.Auth)
user.POST("/record/get", controller.GetRecord, midware.Auth)
user.POST("/url/get", controller.GetUrl, midware.Auth)
url := e.Group("url")
url.Use(midware.Auth)
url.POST("/create", controller.Create)
url.POST("/query", controller.Query)
url.POST("/update", controller.Update)
url.POST("/delete", controller.Delete)
url.POST("/pause", controller.Pause)
}
module go-svc-tpl
go 1.17
require (
github.com/go-playground/validator/v10 v10.10.0
github.com/labstack/echo/v4 v4.9.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/viper v1.10.1
github.com/swaggo/echo-swagger v1.3.5
gorm.io/driver/mysql v1.2.3
gorm.io/gorm v1.22.5
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.4 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
github.com/swaggo/swag v1.8.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
This diff is collapsed.
# Golang Service Template
Golang back-end service template. Using this template, you can get started with back-end projects quickly.
| Web Framework | ORM | Database Driver | Configuration Manager | Log Manager | API Documentation |
|:----------------:|:------------:|:--------------------:|:---------------------:|:---------------:|:-------------------:|
| labstack/echo/v4 | gorm.io/gorm | gorm.io/driver/mysql | spf13/viper | sirupsen/logrus | swaggo/echo-swagger |
> forked from go-svc-tpl
## 使用
1. 该模板未建立 model 层,请自己设计表结构,然后完成 model 部分
- 注意,若非使用 `automigrate` 而是手动建表,请附上相应 sql 文档
2. controller 部分请遵循 api 文档,暂时不用管 swagger 部分
## Init
1. create `conf.yaml`
2. use `swag init` to create swagger docs
3. go build & run
// @title Golang Service Template
// @version 0.1
// @description Golang back-end service template, get started with back-end projects quickly
// @BasePath /api
package main
import (
"go-svc-tpl/app"
_ "go-svc-tpl/docs"
"go-svc-tpl/model"
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetReportCaller(true)
model.Init()
app.InitWebFramework()
app.StartServer()
}
package model
// import "fmt"
// // 用于controller测试
// type User struct {
// Email string `json:"email"`
// Password string `json:"password"`
// }
// type ShortLink struct {
// Origin string `form:"origin"`
// Short string `form:"short"`
// Comment string `form:"comment"`
// StartTime int64 `form:"startTime`
// ExpireTime int64 `form:"expireTime`
// } // 创建的那五个参数设置form tag
// type UpdateData struct {
// Origin string `form:"origin"`
// Comment string `form:"comment"`
// StartTime int64 `form:"startTime`
// ExpireTime int64 `form:"expireTime`
// } // 修改的那四个参数设置form tag
// func RegisterUser(name, email, pwd string) error {
// return nil
// }
// func CheckAuth(email, pwd string) bool { // 检查是否有这个用户,密码对不对
// return true
// }
// // 这三个返回一些信息的类型看数据库实现
// func GetUser(name string) (User, error) {
// return User{"1234@zju.edu.cn", "114514"}, nil
// }
// func GetRecord(name string) (interface{}, error) {
// return ShortLink{
// Origin: "1145141919",
// Short: "114",
// Comment: "henhenaaaa",
// StartTime: 0,
// ExpireTime: 10000,
// }, nil
// }
// func GetUrl(name string) (interface{}, error) {
// return "urlurlurl", nil
// }
// // 意义显然x
// func CreateLink(name string, link ShortLink) (int, error) {
// fmt.Println(name)
// return 1, nil
// }
// func QueryLink(name string, id int) (ShortLink, error) {
// fmt.Printf("%s%d\n", name, id)
// return ShortLink{
// Origin: "1145141919",
// Short: "114",
// Comment: "henhenaaaa",
// StartTime: 0,
// ExpireTime: 10000,
// }, nil
// }
// func UpdateLink(name string, data UpdateData) error {
// fmt.Printf("%s%+v\n", name, data)
// return nil
// }
// func DeleteLink(name string, id int) error {
// fmt.Printf("%s%d\n", name, id)
// return nil
// }
// func PauseLink(name string, id int) error {
// fmt.Printf("%s%d\n", name, id)
// return nil
// }
// func ExistShort(str string) bool { // 短链接是否已经存在
// return false
// }
package model
import (
"errors"
)
// TODO: add crud interface here
func RegisterUser(name, email, pwd string) error {
newUser := User{}
newUser.Name = name
newUser.Pwd = pwd
newUser.Email = email
newUser.Id = 0
newUser.Number = 0
//create the information of the user
err := DB.Create(&newUser)
if err != nil {
var errReturn = errors.New("fail to register the user")
return errReturn
}
return nil
}
func Login(name, ip string, time int64) error {
targetUser := User{Name: name}
err := DB.Find(&targetUser)
if err != nil {
var errReturn = errors.New("fail to find the user")
return errReturn
}
//get the login information of the user
newRecord := Record{Name: name}
newRecord.Id = targetUser.Number
newRecord.Ip = ip
newRecord.Time = time
//set the record
err1 := DB.Create(&newRecord)
if err1 != nil {
var err1Return = errors.New("fail to register the user")
return err1Return
}
targetUser.Number = targetUser.Number + 1
targetUser.Status = true
//change the status of the user
err2 := DB.Updates(&targetUser)
if err2 != nil {
var err2Return = errors.New("fail to update the information of the user")
return err2Return
}
//update the information of the user
return nil
}
func Logout(name string) error {
targetUser := User{Name: name}
err := DB.Find(&targetUser)
if err != nil {
var errReturn = errors.New("fail to find the user")
return errReturn
}
targetUser.Status = false
//change the status of the user
err1 := DB.Updates(&targetUser)
if err1 != nil {
var err1Return = errors.New("fail to update the information of the user")
return err1Return
}
return nil
}
func CheckAuth(email, pwd string) bool {
targetUser := User{Email: email}
err := DB.Find(&targetUser)
if err != nil {
return false
}
if targetUser.Pwd != pwd {
return false
}
return true
}
func GetUser(name string) (interface{}, error) {
var targetUser []User
err := DB.Where(map[string]interface{}{"name": name}).Find(&targetUser)
if err != nil {
var errReturn = errors.New("fail to find the user")
return nil, errReturn
}
return targetUser, nil
}
func GetRecord(name string) (interface{}, error) {
master := User{Name: name}
err := DB.Find(&master)
if err != nil {
var errReturn = errors.New("fail to find the user")
return 0, errReturn
}
targetRecord := Record{Name: name, Id: 0}
err1 := DB.Find(&targetRecord)
if err1 != nil {
var err1Return = errors.New("fail to find the record")
return nil, err1Return
}
result := make([]Record, 0)
result = append(result, targetRecord)
for i := 1; i < master.Number; i++ {
targetLink := Record{Name: name, Id: i}
err2 := DB.Find(&targetLink)
if err2 != nil {
continue
}
result = append(result, targetLink)
}
return result, nil
}
func GetUrl(name string) (interface{}, error) {
master := User{Name: name}
err := DB.Find(&master)
if err != nil {
var errReturn = errors.New("fail to find the user")
return 0, errReturn
}
targetUrl := ShortLink{Name: name, Id: 0}
err1 := DB.Find(&targetUrl)
if err1 != nil {
var err1Return = errors.New("fail to find the record")
return nil, err1Return
}
result := make([]string, 0)
result = append(result, targetUrl.Short)
for i := 1; i < master.Id; i++ {
targetLink := ShortLink{Name: name, Id: i}
err2 := DB.Find(&targetLink)
if err2 != nil {
continue
}
result = append(result, targetLink.Short)
}
return result, nil
}
func CreateLink(name string, link ShortLink) (int, error) {
newLink := link
newLink.Name = name
if link.StartTime < link.ExpireTime {
newLink.Status = true
} else {
newLink.Status = false
}
//set the status of the short link
master := User{Name: name}
err := DB.Find(&master)
if err != nil {
var errReturn = errors.New("fail to find the user")
return 0, errReturn
}
newLink.Id = master.Id
master.Id = master.Id + 1
err1 := DB.Updates(&master)
if err1 != nil {
var err1Return = errors.New("fail to update the information of the user")
return 0, err1Return
}
//update the information of the user
err2 := DB.Create(&newLink)
if err2 != nil {
var err2Return = errors.New("fail to create the link")
return 0, err2Return
}
return newLink.Id, nil
}
func QueryLink(name string, id int) (ShortLink, error) {
targetLink := ShortLink{Name: name, Id: id}
err := DB.Find(&targetLink)
if err != nil {
var errReturn = errors.New("fail to find the short link")
return targetLink, errReturn
}
return targetLink, nil
}
func UpdateLink(name string, data UpdateData) error {
targetLink := ShortLink{Name: name}
err := DB.Find(&targetLink)
if err != nil {
var errReturn = errors.New("fail to find the short link")
return errReturn
}
targetLink.Origin = data.Origin
targetLink.Comment = data.Comment
targetLink.StartTime = data.StartTime
targetLink.ExpireTime = data.ExpireTime
err1 := DB.Updates(&targetLink)
if err1 != nil {
var err1Return = errors.New("fail to update the short link")
return err1Return
}
return nil
}
func DeleteLink(name string, id int) error {
targetLink := ShortLink{Name: name, Id: id}
err := DB.Find(&targetLink)
if err != nil {
var errReturn = errors.New("fail to find the short link")
return errReturn
}
master := User{Name: name}
err1 := DB.Find(&master)
if err1 != nil {
var err1Return = errors.New("fail to find the user")
return err1Return
}
err2 := DB.Delete(&targetLink)
if err2 != nil {
var err2Return = errors.New("fail to delete the short link")
return err2Return
}
//delete the targrt link
master.Id = master.Id - 1
err3 := DB.Updates(&master)
if err3 != nil {
var err3Return = errors.New("fail to update the imformation of the user")
return err3Return
}
//update the information of the user
return nil
}
func PauseLink(name string, id int) error {
targetLink := ShortLink{Name: name, Id: id}
err := DB.Find(&targetLink)
if err != nil {
var errReturn = errors.New("fail to find the short link")
return errReturn
}
targetLink.Status = false
//set the status of the short link false
err1 := DB.Updates(&targetLink)
if err1 != nil {
var err1Return = errors.New("fail to pause the short link")
return err1Return
}
return nil
}
func ExistShort(str string) bool {
targetLink := ShortLink{Short: str, Status: true}
err := DB.Find(&targetLink)
if err != nil {
return false
}
return true
}
package model
// TODO: add new model
type User struct {
Name string `json:"name" form:"name" query:"name"`
Pwd string `json:"pwd" form:"pwd" query:"pwd"`
Email string `json:"email" form:"email" query:"email"`
Status bool `json:"status" form:"status" query:"status"`
Id int //count the number of short link of the user
Number int //count the login number of the user
}
type Record struct {
Name string `json:"name" form:"name" query:"name"` //set the user of the record
Time int64 `json:"time" form:"time" query:"time"`
Ip string `json:"ip" form:"ip" query:"ip"`
Id int
}
type ShortLink struct {
Id int `json:"id" form:"id" query:"id"`
Name string `json:"name" form:"name" query:"name"` //set the user of the short link
Origin string `json:"origin" form:"origin" query:"origin"`
Short string `json:"short" form:"short" query:"short"`
Comment string `json:"comment" form:"comment" query:"comment"`
StartTime int64 `json:"starttime" form:"starttime" query:"starttime"`
ExpireTime int64 `json:"expiretime" form:"expiretime" query:"expiretime"`
Status bool `json:"status" form:"status" query:"status"` //set the status of the short link, if true, we can use the short link, false, not
}
type UpdateData struct {
Origin string `json:"origin" form:"origin" query:"origin"`
Comment string `json:"comment" form:"comment" query:"comment"`
StartTime int64 `json:"starttime" form:"starttime" query:"starttime"`
ExpireTime int64 `json:"expiretime" form:"expiretime" query:"expiretime"`
}
package model
import (
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Init() {
connectDatabase()
err := DB.AutoMigrate(&User{}) // TODO: add table structs here
if err != nil {
logrus.Fatal(err)
}
err1 := DB.AutoMigrate(&ShortLink{})
if err1 != nil {
logrus.Fatal(err1)
}
err2 := DB.AutoMigrate(&Record{})
if err2 != nil {
logrus.Fatal(err1)
}
}
func connectDatabase() {
viper.SetConfigName("conf")
viper.AddConfigPath("./")
if err := viper.ReadInConfig(); err != nil {
logrus.Panic(err)
}
loginInfo := viper.GetStringMapString("sql")
dbArgs := loginInfo["username"] + ":" + loginInfo["password"] +
"@(localhost)/" + loginInfo["db_name"] + "?charset=utf8mb4&parseTime=True&loc=Local"
var err error
DB, err = gorm.Open(mysql.Open(dbArgs), &gorm.Config{})
if err != nil {
logrus.Panic(err)
}
}
package utils
import (
"fmt"
"go-svc-tpl/model"
)
var shortCounter int
var toChar map[int]string
func init() {
shortCounter = 1145141919
toChar = make(map[int]string)
// radix 62
for i := 0; i < 10; i++ {
toChar[i] = fmt.Sprintf("%d", i)
}
for i := 0; i < 26; i++ {
toChar[i+10] = fmt.Sprintf("%c", 'A'+i)
toChar[i+36] = fmt.Sprintf("%c", 'a'+i)
}
}
// generate shortlink
func GenShort() string {
short := ""
for i := shortCounter; i != 0; i /= 62 {
short = fmt.Sprintf("%s%s", short, toChar[i%62])
}
shortCounter++
// while short exists, generate again
for model.ExistShort(short) {
short = GenShort()
}
return short
}
package utils
import (
"time"
"github.com/dgrijalva/jwt-go"
)
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
var jwtSecret = []byte("woshinibaba") // secret key used to gen token
// get token from (username, password)
func GenToken(username, password string) (string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(2 * time.Hour) // expire after 2 hours
claims := Claims{
Username: username,
Password: password,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: "nibaba",
},
}
// sign
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
// take token into Claims{}, and then can get username and password
func ParseToken(token string) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(t *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
}