登录与授权等
This commit is contained in:
parent
968eab9b06
commit
ec548f4256
|
@ -5,12 +5,12 @@ import (
|
||||||
"mc-client-updater-server/internal/service"
|
"mc-client-updater-server/internal/service"
|
||||||
"mc-client-updater-server/pkg/param"
|
"mc-client-updater-server/pkg/param"
|
||||||
"mc-client-updater-server/pkg/result"
|
"mc-client-updater-server/pkg/result"
|
||||||
|
"mc-client-updater-server/pkg/util"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleLogin(c *gin.Context) {
|
func HandleLogin(c *gin.Context) {
|
||||||
srv := service.NewUserService(c)
|
|
||||||
res := result.NewResult(c)
|
res := result.NewResult(c)
|
||||||
|
|
||||||
loginParam := param.LoginParam{}
|
loginParam := param.LoginParam{}
|
||||||
err := c.ShouldBindJSON(&loginParam)
|
err := c.ShouldBindJSON(&loginParam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,6 +18,62 @@ func HandleLogin(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srv := service.NewUserService(c)
|
||||||
srv.Login(loginParam.Username, loginParam.Password)
|
srv.Login(loginParam.Username, loginParam.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleGrantAdd(c *gin.Context) {
|
||||||
|
res := result.NewResult(c)
|
||||||
|
p := param.NewGrantTokenParam{}
|
||||||
|
err := c.ShouldBindJSON(&p)
|
||||||
|
if err != nil {
|
||||||
|
res.BadRequest()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.ExpireAt != "" {
|
||||||
|
isValid := util.IsSQLTimeFormat(p.ExpireAt)
|
||||||
|
if !isValid {
|
||||||
|
res.BadRequestWithMsg("请求参数错误:时间格式错误,应为2006-01-02 15:04:05格式")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if p.TTL == 0 {
|
||||||
|
res.BadRequestWithMsg("请求参数错误:至少提供expire_at和ttl中的一项且不为0")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.ExpireAt = util.ToSQLTimeFormat(time.Now().Add(time.Duration(p.TTL) * time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
srv := service.NewInstanceService(c)
|
||||||
|
// 验证 target -> instance(name) 是否存在
|
||||||
|
_, err = srv.GetInstanceByName(p.Target)
|
||||||
|
if err != nil {
|
||||||
|
res.InvalidInstance(p.Target)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
grantEntity, err := srv.NewGrantToken(p.Target, p.ExpireAt)
|
||||||
|
if err != nil {
|
||||||
|
res.InternalServerError("生成授权码失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(grantEntity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleNewInstance(c *gin.Context) {
|
||||||
|
res := result.NewResult(c)
|
||||||
|
p := param.AddInstanceParam{}
|
||||||
|
err := c.ShouldBindJSON(&p)
|
||||||
|
if err != nil {
|
||||||
|
res.BadRequest()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
srv := service.NewInstanceService(c)
|
||||||
|
inst, err := srv.AddInstance(p.Name, p.UpdateURL)
|
||||||
|
if err != nil {
|
||||||
|
res.DuplicatedValue("实例名称已存在")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(inst)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
func HandleInstanceUpdate() {
|
||||||
|
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ func AdminRequired(c *gin.Context) {
|
||||||
res := result.NewResult(c)
|
res := result.NewResult(c)
|
||||||
authorization := c.GetHeader("Authorization")
|
authorization := c.GetHeader("Authorization")
|
||||||
if authorization == "" {
|
if authorization == "" {
|
||||||
res.Unauthorized()
|
res.UnLogin()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,37 @@ package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"mc-client-updater-server/pkg/log"
|
"gorm.io/gorm"
|
||||||
|
"mc-client-updater-server/internal/service"
|
||||||
|
"mc-client-updater-server/pkg/result"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GrantRequired(c *gin.Context) {
|
func GrantRequired(c *gin.Context) {
|
||||||
instName := c.Param("name")
|
instName := c.Param("name")
|
||||||
log.Logger.Info(instName)
|
// 判断instance name是否存在
|
||||||
|
srv := service.NewInstanceService(c)
|
||||||
|
res := result.NewResult(c)
|
||||||
|
instEntity, err := srv.GetInstanceByName(instName)
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
res.InvalidInstance(instName)
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
res.InternalServerError("查询实例对象时出现错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("instance", instEntity)
|
||||||
|
|
||||||
|
// 判断grant_code是否合法
|
||||||
|
grantCode := c.GetHeader("GrantCode")
|
||||||
|
if grantCode == "" {
|
||||||
|
res.Unauthorized()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
grantEntity, err := srv.GetGrantByToken(grantCode)
|
||||||
|
if err != nil {
|
||||||
|
res.Unauthorized()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("grant", grantEntity)
|
||||||
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func NewRouter() *gin.Engine {
|
||||||
*/
|
*/
|
||||||
inst := v1.Group("/instance/:name", middleware.GrantRequired)
|
inst := v1.Group("/instance/:name", middleware.GrantRequired)
|
||||||
{
|
{
|
||||||
inst.GET("/detail")
|
inst.POST("/upload", )
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,9 +37,8 @@ func NewRouter() *gin.Engine {
|
||||||
*/
|
*/
|
||||||
admin := v1.Group("/admin", middleware.AdminRequired)
|
admin := v1.Group("/admin", middleware.AdminRequired)
|
||||||
{
|
{
|
||||||
admin.GET("/instances")
|
admin.POST("/new_instance", handler.HandleNewInstance)
|
||||||
admin.GET("/users")
|
admin.POST("/grant/add", handler.HandleGrantAdd)
|
||||||
admin.GET("/updates")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"mc-client-updater-server/pkg/dao"
|
||||||
|
"mc-client-updater-server/pkg/dao/entity"
|
||||||
|
"mc-client-updater-server/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstanceService struct {
|
||||||
|
ctx *gin.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInstanceService(c *gin.Context) *InstanceService {
|
||||||
|
return &InstanceService{ctx: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InstanceService) AddInstance(name, updateURL string) (*entity.Instance, error) {
|
||||||
|
instEntity := entity.Instance{
|
||||||
|
Name: name,
|
||||||
|
UpdateURL: updateURL,
|
||||||
|
}
|
||||||
|
tx := dao.DB().Create(&instEntity)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return nil, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = dao.DB().Where(&instEntity).Last(&instEntity)
|
||||||
|
return &instEntity, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InstanceService) GetInstanceByName(name string) (*entity.Instance, error) {
|
||||||
|
instEntity := entity.Instance{}
|
||||||
|
tx := dao.DB().Where("name=?", name).Last(&instEntity)
|
||||||
|
return &instEntity, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InstanceService) NewGrantToken(instName string, expireStr string) (*entity.Grant, error) {
|
||||||
|
expireAt := util.MustParseSQLTime(expireStr)
|
||||||
|
grantEntity := entity.Grant{GrantTo: instName, ExpireAt: expireAt, Token: util.RandStr(32)}
|
||||||
|
tx := dao.DB().Create(&grantEntity)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return nil, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = dao.DB().Where(&grantEntity).Last(&grantEntity)
|
||||||
|
return &grantEntity, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InstanceService) GetGrantByToken(token string) (*entity.Grant, error) {
|
||||||
|
grantEntity := entity.Grant{}
|
||||||
|
tx := dao.DB().Where("token=?", token).Last(&grantEntity)
|
||||||
|
return &grantEntity, tx.Error
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ func (s *TokenService) VerifyToken(token string) (*entity.Token, bool) {
|
||||||
// 是否存在
|
// 是否存在
|
||||||
tokenRow := s.getToken(token)
|
tokenRow := s.getToken(token)
|
||||||
if tokenRow == nil {
|
if tokenRow == nil {
|
||||||
res.Unauthorized()
|
res.UnLogin()
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
// 是否过期
|
// 是否过期
|
||||||
|
@ -34,8 +34,8 @@ func (s *TokenService) VerifyToken(token string) (*entity.Token, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TokenService) getToken(token string) *entity.Token {
|
func (s *TokenService) getToken(token string) *entity.Token {
|
||||||
tokenRow := entity.Token{Token: token}
|
tokenRow := entity.Token{}
|
||||||
tx := dao.DB().Last(&tokenRow)
|
tx := dao.DB().Where("token=?", token).Last(&tokenRow)
|
||||||
if tx.Error == gorm.ErrRecordNotFound {
|
if tx.Error == gorm.ErrRecordNotFound {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ func (s *TokenService) getToken(token string) *entity.Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TokenService) getTokenByUsername(username string) *entity.Token {
|
func (s *TokenService) getTokenByUsername(username string) *entity.Token {
|
||||||
tokenRow := entity.Token{GrantTo: username}
|
tokenRow := entity.Token{}
|
||||||
tx := dao.DB().First(&tokenRow)
|
tx := dao.DB().Where("grant_to=?", username).Last(&tokenRow)
|
||||||
if tx.Error == gorm.ErrRecordNotFound {
|
if tx.Error == gorm.ErrRecordNotFound {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ func (s *UserService) hasRole(role string, user *entity.User) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UserService) getUserByUsername(name string) *entity.User {
|
func (s *UserService) getUserByUsername(name string) *entity.User {
|
||||||
user := entity.User{Username: name}
|
user := entity.User{}
|
||||||
tx := dao.DB().First(&user)
|
tx := dao.DB().Where("username=?", name).First(&user)
|
||||||
if tx.Error != nil {
|
if tx.Error != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
2000 用户操作错误
|
||||||
|
3000 预留
|
||||||
|
4000 数据库操作错误
|
||||||
|
5000 系统错误
|
||||||
|
*/
|
||||||
const (
|
const (
|
||||||
LoginErrorCode = 2001
|
LoginErrorCode = 2001
|
||||||
NoPermission = 2002
|
NoPermission = 2002
|
||||||
LoginExpired = 2003
|
LoginExpired = 2003
|
||||||
|
InvalidInstance = 2004
|
||||||
|
|
||||||
|
DuplicatedValue = 4001
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,6 +69,7 @@ func migrate() {
|
||||||
err = db.AutoMigrate(&entity.Update{})
|
err = db.AutoMigrate(&entity.Update{})
|
||||||
err = db.AutoMigrate(&entity.Grant{})
|
err = db.AutoMigrate(&entity.Grant{})
|
||||||
err = db.AutoMigrate(&entity.Token{})
|
err = db.AutoMigrate(&entity.Token{})
|
||||||
|
err = db.AutoMigrate(&entity.Metadata{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Fatal("关联数据表失败:", err)
|
log.Logger.Fatal("关联数据表失败:", err)
|
||||||
|
|
|
@ -2,12 +2,13 @@ package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Grant Grant是授权给实例的,给予实例访问权限
|
// Grant Grant是授权给实例的,给予实例访问权限
|
||||||
type Grant struct {
|
type Grant struct {
|
||||||
gorm.Model `json:"model"`
|
gorm.Model `json:"model"`
|
||||||
Token string `gorm:"unique;not null" json:"token,omitempty"`
|
Token string `gorm:"unique;not null" json:"token"`
|
||||||
TTL int `gorm:"not null;default:0" json:"ttl,omitempty"`
|
ExpireAt time.Time `gorm:"index" json:"expire_at"`
|
||||||
GrantTo uint `gorm:"not null;default:0;comment:instances(id) 授权给实例,0表示无指定(所有)" json:"grant_to,omitempty"`
|
GrantTo string `gorm:"not null;default:'';comment:instances(name)授权给实例,空表示无指定(所有)" json:"grant_to"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ import (
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
gorm.Model `json:"model"`
|
gorm.Model `json:"model"`
|
||||||
Name string `gorm:"unique;not null" json:"name,omitempty"`
|
Name string `gorm:"unique;not null" json:"name"`
|
||||||
UpdateURL string `gorm:"column:update_url;not null;default:'';comment:更新URL,未指定使用默认" json:"update_url,omitempty"`
|
UpdateURL string `gorm:"column:update_url;not null;default:'';comment:更新URL,未指定使用默认" json:"update_url"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Key string `gorm:"unique;not null" json:"key"`
|
||||||
|
Value string `gorm:"not null;default:''" json:"value"`
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import "gorm.io/gorm"
|
||||||
// Token Token是授权给用户的,给予用户登录权限
|
// Token Token是授权给用户的,给予用户登录权限
|
||||||
type Token struct {
|
type Token struct {
|
||||||
gorm.Model `json:"model"`
|
gorm.Model `json:"model"`
|
||||||
Token string `gorm:"unique;not null" json:"token,omitempty"`
|
Token string `gorm:"unique;not null" json:"token"`
|
||||||
GrantTo string `gorm:"index;not null;default:''" json:"grant_to,omitempty"`
|
GrantTo string `gorm:"index;not null;default:''" json:"grant_to"`
|
||||||
TTL int `gorm:"not null;default:0" json:"ttl,omitempty"`
|
TTL int `gorm:"not null;default:0" json:"ttl"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import "gorm.io/gorm"
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
gorm.Model `json:"model"`
|
gorm.Model `json:"model"`
|
||||||
HashID string `gorm:"index;not null" json:"hash_id,omitempty"`
|
HashID string `gorm:"index;not null" json:"hash_id"`
|
||||||
Comment string `gorm:"not null;default:'';comment:更新内容或注释" json:"comment,omitempty"`
|
Comment string `gorm:"not null;default:'';comment:更新内容或注释" json:"comment"`
|
||||||
Changes string `gorm:"not null;comment:更改的文件列表,逗号分隔,引用files(hash_id)" json:"changes,omitempty"`
|
Changes string `gorm:"not null;comment:更改的文件列表,逗号分隔,引用files(hash_id)" json:"changes"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import "gorm.io/gorm"
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model `json:"model"`
|
gorm.Model `json:"model"`
|
||||||
Username string `gorm:"unique;not null" json:"username,omitempty"`
|
Username string `gorm:"unique;not null" json:"username"`
|
||||||
Password string `gorm:"not null" json:"password,omitempty"`
|
Password string `gorm:"not null" json:"password"`
|
||||||
Roles string `gorm:"not null;default:''" json:"roles,omitempty"`
|
Roles string `gorm:"not null;default:''" json:"roles"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package param
|
|
||||||
|
|
||||||
type AuthorizeQueryParam struct {
|
|
||||||
ClientId uint `form:"client_id" binding:"required"`
|
|
||||||
ResponseType string `form:"response_type" binding:"required"`
|
|
||||||
State string `form:"state" binding:"required"`
|
|
||||||
Scope string `form:"scope" binding:"required"`
|
|
||||||
CodeChallenge string `form:"code_challenge" binding:"required"`
|
|
||||||
CodeChallengeMethod string `form:"code_challenge_method" binding:"required"`
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package param
|
||||||
|
|
||||||
|
type AddInstanceParam struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
UpdateURL string `json:"update_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NewGrantTokenParam struct {
|
||||||
|
Target string `json:"target" binding:"required"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
ExpireAt string `json:"expire_at"`
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package param
|
package param
|
||||||
|
|
||||||
type LoginParam struct {
|
type LoginParam struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username" binding:"required"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func (r *Result) Fail(code int, msg string) {
|
||||||
res := Root{
|
res := Root{
|
||||||
Code: code,
|
Code: code,
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
Data: gin.H{},
|
Data: nil,
|
||||||
}
|
}
|
||||||
r.ctx.JSON(http.StatusOK, res)
|
r.ctx.JSON(http.StatusOK, res)
|
||||||
r.ctx.Abort()
|
r.ctx.Abort()
|
||||||
|
@ -57,14 +57,22 @@ func (r *Result) BadRequest() {
|
||||||
r.Fail(http.StatusBadRequest, "请求参数错误")
|
r.Fail(http.StatusBadRequest, "请求参数错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Result) BadRequestWithMsg(msg string) {
|
||||||
|
r.Fail(http.StatusBadRequest, msg)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Result) LoginError() {
|
func (r *Result) LoginError() {
|
||||||
r.Fail(common.LoginErrorCode, "账号或密码错误")
|
r.Fail(common.LoginErrorCode, "账号或密码错误")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Unauthorized() {
|
func (r *Result) UnLogin() {
|
||||||
r.Fail(http.StatusUnauthorized, "未登录")
|
r.Fail(http.StatusUnauthorized, "未登录")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Result) Unauthorized() {
|
||||||
|
r.Fail(http.StatusUnauthorized, "未授权")
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Result) NoPermission() {
|
func (r *Result) NoPermission() {
|
||||||
r.Fail(common.NoPermission, "权限不足")
|
r.Fail(common.NoPermission, "权限不足")
|
||||||
}
|
}
|
||||||
|
@ -72,3 +80,11 @@ func (r *Result) NoPermission() {
|
||||||
func (r *Result) LoginExpired() {
|
func (r *Result) LoginExpired() {
|
||||||
r.Fail(common.LoginExpired, "登录过期")
|
r.Fail(common.LoginExpired, "登录过期")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Result) DuplicatedValue(msg string) {
|
||||||
|
r.Fail(common.DuplicatedValue, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) InvalidInstance(instName string) {
|
||||||
|
r.Fail(common.InvalidInstance, "指定的实例不存在:"+instName)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func ToSQLTimeFormat(t time.Time) string {
|
||||||
|
return t.Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustParseSQLTime(timeStr string) time.Time {
|
||||||
|
timeObj, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return timeObj
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSQLTimeFormat(timeStr string) bool {
|
||||||
|
_, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
func GenSessionID() string {
|
|
||||||
return RandStr(32)
|
|
||||||
}
|
|
Loading…
Reference in New Issue