feat: token gen

v3
veypi 2 months ago
parent 14931a51e5
commit 3948d51728

@ -1,16 +1,21 @@
package token package token
import ( import (
"encoding/hex"
"oa/cfg" "oa/cfg"
"oa/errs"
"oa/libs/auth"
M "oa/models" M "oa/models"
"strings" "time"
"github.com/google/uuid" "github.com/golang-jwt/jwt/v5"
"github.com/veypi/OneBD/rest" "github.com/veypi/OneBD/rest"
"github.com/veypi/utils"
"github.com/veypi/utils/logv"
) )
func useToken(r rest.Router) { func useToken(r rest.Router) {
r.Get("/salt/:id", tokenSalt) r.Post("/salt", tokenSalt)
r.Post("/", tokenPost) r.Post("/", tokenPost)
r.Get("/:token_id", tokenGet) r.Get("/:token_id", tokenGet)
r.Patch("/:token_id", tokenPatch) r.Patch("/:token_id", tokenPatch)
@ -24,10 +29,100 @@ func tokenSalt(x *rest.X) (any, error) {
return nil, err return nil, err
} }
data := &M.User{} data := &M.User{}
query := "username = ?"
if opts.Typ == nil {
} else if *opts.Typ == "email" {
query = "email = ?"
} else if *opts.Typ == "phone" {
query = "phone = ?"
}
err = cfg.DB().Where("id = ?", opts.ID).First(data).Error err = cfg.DB().Where(query, opts.Username).First(data).Error
return data.Salt, err return map[string]string{"salt": data.Salt, "id": data.ID}, err
}
// for user login app
func tokenPost(x *rest.X) (any, error) {
opts := &M.TokenPost{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
aid := cfg.Config.ID
if opts.AppID != nil {
aid = *opts.AppID
}
data := &M.Token{}
claim := &auth.Claims{}
claim.IssuedAt = jwt.NewNumericDate(time.Now())
claim.Issuer = "oa"
if opts.Token != nil {
// for other app redirect
oldClaim, err := auth.ParseJwt(*opts.Token)
if err != nil {
return nil, err
} }
err = cfg.DB().Where("id = ?", oldClaim.ID).First(data).Error
if err != nil {
return nil, err
}
if oldClaim.AID == *opts.AppID {
// refresh token
} else {
// gen other app token
}
} else if opts.Salt != nil && opts.Code != nil && aid == cfg.Config.ID {
// for oa login
user := &M.User{}
err = cfg.DB().Where("id = ?", opts.UserID).Find(user).Error
if err != nil {
return nil, err
}
logv.Info().Str("user", user.ID).Msg("login")
code := *opts.Code
salt := logv.AssertFuncErr(hex.DecodeString(*opts.Salt))
key := logv.AssertFuncErr(hex.DecodeString(user.Code))
logv.Warn().Msgf("%d: %d", len(key), len(salt))
logv.Warn().Msgf("%s: %s", user.Code, *opts.Salt)
de, err := utils.AesDecrypt([]byte(code), key, salt)
if err != nil || de != user.ID {
return nil, errs.AuthInvalid
}
data.UserID = opts.UserID
data.AppID = aid
if opts.ExpiredAt != nil {
data.ExpiredAt = *opts.ExpiredAt
} else {
data.ExpiredAt = time.Now().Add(time.Hour * 72)
}
if opts.OverPerm != nil {
data.OverPerm = *opts.OverPerm
}
// logv.AssertError(cfg.DB().Create(data).Error)
claim.AID = aid
claim.UID = user.ID
claim.Name = user.Username
claim.Icon = user.Icon
if user.Nickname != "" {
claim.Name = user.Nickname
}
acList := make(auth.Access, 0, 10)
logv.AssertError(cfg.DB().Debug().Table("accesses a").
Select("a.name, a.t_id, a.level").
Joins("INNER JOIN user_roles ur ON ur.role_id = a.role_id AND ur.user_id = ?", user.ID).
Scan(&acList).Error)
claim.Access = acList
token := logv.AssertFuncErr(auth.GenJwt(claim))
return map[string]string{"refresh": token, "token": token}, err
} else {
return nil, errs.ArgsInvalid
}
claim.ExpiresAt = jwt.NewNumericDate(data.ExpiredAt)
err = cfg.DB().Create(data).Error
return data, err
}
func tokenGet(x *rest.X) (any, error) { func tokenGet(x *rest.X) (any, error) {
opts := &M.TokenGet{} opts := &M.TokenGet{}
err := x.Parse(opts) err := x.Parse(opts)
@ -75,27 +170,6 @@ func tokenDelete(x *rest.X) (any, error) {
return data, err return data, err
} }
func tokenPost(x *rest.X) (any, error) {
opts := &M.TokenPost{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
data := &M.Token{}
data.ID = strings.ReplaceAll(uuid.New().String(), "-", "")
data.UserID = opts.UserID
data.AppID = opts.AppID
if opts.ExpiredAt != nil {
data.ExpiredAt = *opts.ExpiredAt
}
if opts.OverPerm != nil {
data.OverPerm = *opts.OverPerm
}
err = cfg.DB().Create(data).Error
return data, err
}
func tokenList(x *rest.X) (any, error) { func tokenList(x *rest.X) (any, error) {
opts := &M.TokenList{} opts := &M.TokenList{}
err := x.Parse(opts) err := x.Parse(opts)

@ -12,6 +12,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/veypi/OneBD/rest" "github.com/veypi/OneBD/rest"
"gorm.io/gorm"
) )
func useUser(r rest.Router) { func useUser(r rest.Router) {
@ -121,8 +122,8 @@ func userPost(x *rest.X) (any, error) {
data.Username = opts.Username data.Username = opts.Username
data.Salt = opts.Salt data.Salt = opts.Salt
data.Code = opts.Code data.Code = opts.Code
if data.Username == "" || len(data.Salt) != 32 || len(data.Code) != 256 { if data.Username == "" || len(data.Salt) != 32 || len(data.Code) != 64 {
return nil, errs.ArgsInvalid return nil, errs.ArgsInvalid.WithStr("username/salt/code length")
} }
if opts.Nickname != nil { if opts.Nickname != nil {
data.Nickname = *opts.Nickname data.Nickname = *opts.Nickname
@ -139,9 +140,26 @@ func userPost(x *rest.X) (any, error) {
data.Phone = *opts.Phone data.Phone = *opts.Phone
} }
data.Status = 1 data.Status = 1
err = cfg.DB().Create(data).Error err = cfg.DB().Transaction(func(tx *gorm.DB) error {
err := tx.Create(data).Error
if err != nil { if err != nil {
return nil, err return err
}
app := &M.App{}
err = tx.Where("id = ?", cfg.Config.ID).First(app).Error
if err != nil {
return err
} }
status := "ok"
if app.Participate != "auto" {
status = "applying"
}
return tx.Create(&M.AppUser{
UserID: data.ID,
AppID: cfg.Config.ID,
Status: status,
}).Error
})
return data, nil return data, nil
} }

@ -9,6 +9,7 @@ package cfg
import ( import (
"github.com/veypi/OneBD/rest" "github.com/veypi/OneBD/rest"
"github.com/veypi/utils"
"github.com/veypi/utils/flags" "github.com/veypi/utils/flags"
"github.com/veypi/utils/logv" "github.com/veypi/utils/logv"
) )
@ -16,7 +17,8 @@ import (
type config struct { type config struct {
rest.RestConf rest.RestConf
DSN string `json:"dsn"` DSN string `json:"dsn"`
JWT string `json:"jwt"` ID string `json:"id"`
Key string `json:"key"`
} }
var Config = &config{} var Config = &config{}
@ -34,6 +36,12 @@ func init() {
CMD.Before = func() error { CMD.Before = func() error {
flags.LoadCfg(*configFile, Config) flags.LoadCfg(*configFile, Config)
CMD.Parse() CMD.Parse()
if Config.Key == "" {
Config.Key = utils.RandSeq(32)
}
if Config.ID == "" {
Config.ID = utils.RandSeq(32)
}
logv.SetLevel(logv.AssertFuncErr(logv.ParseLevel(Config.LoggerLevel))) logv.SetLevel(logv.AssertFuncErr(logv.ParseLevel(Config.LoggerLevel)))
return nil return nil
} }

@ -15,8 +15,8 @@ import (
var db *gorm.DB var db *gorm.DB
var cmdDB = CMD.SubCommand("db", "database operations") var CmdDB = CMD.SubCommand("db", "database operations")
var cmdMigrate = cmdDB.SubCommand("migrate", "migrate database") var cmdMigrate = CmdDB.SubCommand("migrate", "migrate database")
var ObjList = make([]any, 0, 10) var ObjList = make([]any, 0, 10)
func init() { func init() {
@ -31,7 +31,7 @@ func init() {
DB().DisableForeignKeyConstraintWhenMigrating = false DB().DisableForeignKeyConstraintWhenMigrating = false
return DB().AutoMigrate(ObjList...) return DB().AutoMigrate(ObjList...)
} }
cmdDB.SubCommand("drop", "drop database").Command = func() error { CmdDB.SubCommand("drop", "drop database").Command = func() error {
return DB().Migrator().DropTable(ObjList...) return DB().Migrator().DropTable(ObjList...)
} }
} }

@ -24,8 +24,13 @@ func JsonResponse(x *rest.X, data any) error {
} }
func JsonErrorResponse(x *rest.X, err error) { func JsonErrorResponse(x *rest.X, err error) {
code := 50000 code, msg := errIter(err)
var msg string x.WriteHeader(code / 100)
x.JSON(map[string]any{"code": code, "err": msg})
}
func errIter(err error) (code int, msg string) {
code = 50000
switch e := err.(type) { switch e := err.(type) {
case *CodeErr: case *CodeErr:
code = e.Code code = e.Code
@ -38,6 +43,8 @@ func JsonErrorResponse(x *rest.X, err error) {
logv.Warn().Msgf("unhandled db error %d: %s", e.Number, err) logv.Warn().Msgf("unhandled db error %d: %s", e.Number, err)
msg = "db error" msg = "db error"
} }
case interface{ Unwrap() error }:
return errIter(e.Unwrap())
default: default:
if errors.Is(e, gorm.ErrRecordNotFound) { if errors.Is(e, gorm.ErrRecordNotFound) {
code = NotFound.Code code = NotFound.Code
@ -50,8 +57,7 @@ func JsonErrorResponse(x *rest.X, err error) {
msg = e.Error() msg = e.Error()
} }
} }
x.WriteHeader(code / 100) return
x.JSON(map[string]any{"code": code, "err": msg})
} }
type CodeErr struct { type CodeErr struct {
@ -64,13 +70,19 @@ func (c *CodeErr) Error() string {
} }
func (c *CodeErr) WithErr(e error) error { func (c *CodeErr) WithErr(e error) error {
c.Msg = fmt.Errorf("%s: %w", c.Msg, e).Error() nerr := &CodeErr{
return c Code: c.Code,
Msg: fmt.Errorf("%s: %w", c.Msg, e).Error(),
}
return nerr
} }
func (c *CodeErr) WithStr(m string) error { func (c *CodeErr) WithStr(m string) error {
c.Msg = fmt.Errorf("%s: %s", c.Msg, m).Error() nerr := &CodeErr{
return c Code: c.Code,
Msg: fmt.Errorf("%s: %s", c.Msg, m).Error(),
}
return nerr
} }
// New creates a new CodeMsg. // New creates a new CodeMsg.
@ -87,4 +99,5 @@ var (
AuthInvalid = New(40103, "auth invalid") AuthInvalid = New(40103, "auth invalid")
AuthNoPerm = New(40104, "no permission") AuthNoPerm = New(40104, "no permission")
NotFound = New(40400, "not found") NotFound = New(40400, "not found")
DBError = New(50010, "db error")
) )

@ -21,7 +21,7 @@ const (
DoAll = 5 DoAll = 5
) )
type Access []struct { type Access []*struct {
Name string `json:"name"` Name string `json:"name"`
TID string `json:"tid"` TID string `json:"tid"`
Level AuthLevel `json:"level"` Level AuthLevel `json:"level"`
@ -43,6 +43,7 @@ func (a *Access) Check(target string, tid string, l AuthLevel) bool {
type Claims struct { type Claims struct {
UID string `json:"uid"` UID string `json:"uid"`
AID string `json:"aid"`
Name string `json:"name"` Name string `json:"name"`
Icon string `json:"icon"` Icon string `json:"icon"`
Access Access `json:"access"` Access Access `json:"access"`

@ -21,16 +21,31 @@ import (
func GenJwt(claim *Claims) (string, error) { func GenJwt(claim *Claims) (string, error) {
if claim.ExpiresAt == nil { if claim.ExpiresAt == nil {
claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(5 * time.Minute)) claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Hour))
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
tokenString, err := token.SignedString(cfg.Config.JWT) tokenString, err := token.SignedString([]byte(cfg.Config.Key))
if err != nil { if err != nil {
return "", err return "", err
} }
return tokenString, nil return tokenString, nil
} }
func ParseJwt(tokenString string) (*Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(cfg.Config.Key), nil
})
if err != nil || !token.Valid {
return nil, errs.AuthInvalid
}
return claims, nil
}
func CheckJWT(x *rest.X) (*Claims, error) { func CheckJWT(x *rest.X) (*Claims, error) {
authHeader := x.Request.Header.Get("Authorization") authHeader := x.Request.Header.Get("Authorization")
if authHeader == "" { if authHeader == "" {
@ -43,17 +58,11 @@ func CheckJWT(x *rest.X) (*Claims, error) {
} }
// Parse the token // Parse the token
claims := &Claims{} claims, err := ParseJwt(tokenString)
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { if err != nil {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, err
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
} }
return []byte(cfg.Config.JWT), nil
})
if err != nil || !token.Valid {
return nil, errs.AuthInvalid
}
x.Request = x.Request.WithContext(context.WithValue(x.Request.Context(), "uid", claims.ID)) x.Request = x.Request.WithContext(context.WithValue(x.Request.Context(), "uid", claims.ID))
return claims, nil return claims, nil
} }

@ -17,5 +17,5 @@ type AccessPost struct {
RoleID *string `json:"role_id" gorm:"index;type:varchar(32);default: null" parse:"json"` RoleID *string `json:"role_id" gorm:"index;type:varchar(32);default: null" parse:"json"`
Name string `json:"name" parse:"json"` Name string `json:"name" parse:"json"`
TID string `json:"tid" parse:"json"` TID string `json:"tid" parse:"json"`
Level string `json:"level" parse:"json"` Level uint `json:"level" parse:"json"`
} }

@ -10,15 +10,16 @@ package models
type Access struct { type Access struct {
BaseDate BaseDate
AppID string `json:"app_id" gorm:"index;type:varchar(32)" methods:"post,list" parse:"json"` AppID string `json:"app_id" gorm:"index;type:varchar(32)" methods:"post,list" parse:"json"`
App *App `json:"app" gorm:"foreignKey:ID;references:AppID"` App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
UserID *string `json:"user_id" gorm:"index;type:varchar(32);default: null" methods:"post,list" parse:"json"` UserID *string `json:"user_id" gorm:"index;type:varchar(32);default: null" methods:"post,list" parse:"json"`
User *User `json:"user"` User *User `json:"-" gorm:"foreignKey:UserID;references:ID"`
RoleID *string `json:"role_id" gorm:"index;type:varchar(32);default: null" methods:"post,list" parse:"json"` RoleID *string `json:"role_id" gorm:"index;type:varchar(32);default: null" methods:"post,list" parse:"json"`
Role *Role `json:"role"` Role *Role `json:"-" gorm:"foreignKey:RoleID;references:ID"`
Name string `json:"name" methods:"post,*list" parse:"json"` Name string `json:"name" methods:"post,*list" parse:"json"`
TID string `json:"tid" methods:"post" parse:"json"` TID string `json:"tid" methods:"post" parse:"json"`
Level string `json:"level" methods:"post" parse:"json"` Level uint `json:"level" methods:"post" parse:"json"`
} }

@ -1,13 +1,18 @@
package models package models
import (
"github.com/veypi/utils/logv"
"gorm.io/gorm"
)
type App struct { type App struct {
BaseModel BaseModel
Name string `json:"name" methods:"get,post,*patch,*list" parse:"json"` Name string `json:"name" methods:"get,post,*patch,*list" parse:"json"`
Icon string `json:"icon" methods:"post,*patch" parse:"json"` Icon string `json:"icon" methods:"post,*patch" parse:"json"`
Des string `json:"des" methods:"post,*patch" parse:"json"` Des string `json:"des" methods:"post,*patch" parse:"json"`
Participate string `json:"participate" gorm:"default:auto" methods:"post,*patch" parse:"json"` Participate string `json:"participate" gorm:"default:auto" methods:"post,*patch" parse:"json"`
InitRoleID string `json:"init_role_id" gorm:"index;type:varchar(32)" methods:"*patch" parse:"json"` InitRoleID *string `json:"init_role_id" gorm:"index;type:varchar(32);default: null" methods:"*patch" parse:"json"`
InitRole *Role `json:"init_role" gorm:"foreignKey:ID;references:InitRoleID"` InitRole *Role `json:"init_role" gorm:"foreignKey:InitRoleID;references:ID"`
InitUrl string `json:"init_url"` InitUrl string `json:"init_url"`
UserCount uint `json:"user_count"` UserCount uint `json:"user_count"`
Key string `json:"-"` Key string `json:"-"`
@ -15,17 +20,51 @@ type App struct {
type AppUser struct { type AppUser struct {
BaseModel BaseModel
AppID string `json:"app_id" methods:"get,*list,post,*patch" parse:"path"` AppID string `json:"app_id" methods:"get,*list,post" parse:"path"`
App *App `json:"app"` App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
UserID string `json:"user_id" methods:"get,*list,post,*patch" parse:"path"`
User *User `json:"user"` UserID string `json:"user_id" methods:"get,*list,post" parse:"path"`
User *User `json:"-" gorm:"foreignKey:UserID;references:ID"`
Status string `json:"status" methods:"post,*patch,*list" parse:"json"` Status string `json:"status" methods:"post,*patch,*list" parse:"json"`
} }
func (m *AppUser) onOk(tx *gorm.DB) (err error) {
app := &App{}
logv.AssertError(tx.Where("id = ?", m.AppID).First(app).Error)
if app.InitRoleID != nil {
urList := make([]*UserRole, 0, 2)
logv.AssertError(tx.Where("app_id = ? && user_id = ?", m.AppID, m.UserID).Find(&urList).Error)
if len(urList) == 0 {
return tx.Create(&UserRole{
AppID: m.AppID,
UserID: m.UserID,
RoleID: *app.InitRoleID,
Status: "ok",
}).Error
}
}
return nil
}
func (m *AppUser) AfterCreate(tx *gorm.DB) error {
if m.Status == "ok" {
logv.AssertError(m.onOk(tx))
}
return tx.Model(&App{}).Where("id = ?", m.AppID).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
}
func (m *AppUser) AfterUpdate(tx *gorm.DB) error {
if m.Status == "ok" {
return m.onOk(tx)
}
return nil
}
type Resource struct { type Resource struct {
BaseDate BaseDate
AppID string `json:"app_id" gorm:"primaryKey;type:varchar(32)" methods:"post,list,delete" parse:"json"` AppID string `json:"app_id" gorm:"primaryKey;type:varchar(32)" methods:"post,list,delete" parse:"json"`
App *App `json:"app" gorm:"foreignKey:ID;references:AppID"` App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
Name string `json:"name" gorm:"primaryKey" methods:"post,delete" parse:"json"` Name string `json:"name" gorm:"primaryKey" methods:"post,delete" parse:"json"`
Des string `json:"des" methods:"post" parse:"json"` Des string `json:"des" methods:"post" parse:"json"`
} }

@ -7,9 +7,13 @@
package models package models
import ( import (
"gorm.io/gorm"
"oa/cfg" "oa/cfg"
"strings"
"time" "time"
"github.com/google/uuid"
"github.com/veypi/utils/logv"
"gorm.io/gorm"
) )
type BaseModel struct { type BaseModel struct {
@ -18,6 +22,13 @@ type BaseModel struct {
BaseDate BaseDate
} }
func (m *BaseModel) BeforeCreate(tx *gorm.DB) error {
if m.ID == "" {
m.ID = strings.ReplaceAll(uuid.New().String(), "-", "")
}
return nil
}
type BaseDate struct { type BaseDate struct {
CreatedAt time.Time `json:"created_at" methods:"*list" parse:"query"` CreatedAt time.Time `json:"created_at" methods:"*list" parse:"query"`
UpdatedAt time.Time `json:"updated_at" methods:"*list" parse:"query"` UpdatedAt time.Time `json:"updated_at" methods:"*list" parse:"query"`
@ -25,6 +36,7 @@ type BaseDate struct {
} }
func init() { func init() {
cfg.CmdDB.SubCommand("init", "init db data").Command = InitDBData
cfg.ObjList = append(cfg.ObjList, &AppUser{}) cfg.ObjList = append(cfg.ObjList, &AppUser{})
cfg.ObjList = append(cfg.ObjList, &Resource{}) cfg.ObjList = append(cfg.ObjList, &Resource{})
cfg.ObjList = append(cfg.ObjList, &Access{}) cfg.ObjList = append(cfg.ObjList, &Access{})
@ -34,3 +46,43 @@ func init() {
cfg.ObjList = append(cfg.ObjList, &Token{}) cfg.ObjList = append(cfg.ObjList, &Token{})
cfg.ObjList = append(cfg.ObjList, &App{}) cfg.ObjList = append(cfg.ObjList, &App{})
} }
func InitDBData() error {
app := &App{}
app.ID = cfg.Config.ID
logv.AssertError(cfg.DB().Where("id = ?", app.ID).Attrs(app).FirstOrCreate(app).Error)
initRole := map[string]map[string]uint{
"user": {"admin": 5, "normal": 1},
"app": {"admin": 5, "normal": 2},
}
adminID := ""
for r, roles := range initRole {
logv.AssertError(cfg.DB().Where("app_id = ? AND name = ?", app.ID, r).FirstOrCreate(&Resource{
AppID: app.ID,
Name: r,
}).Error)
for rName, l := range roles {
role := &Role{}
logv.AssertError(cfg.DB().Where("app_id = ? AND name = ?", app.ID, rName).Attrs(&Role{
BaseModel: BaseModel{
ID: strings.ReplaceAll(uuid.New().String(), "-", ""),
},
AppID: app.ID,
Name: rName,
}).FirstOrCreate(role).Error)
logv.AssertError(cfg.DB().Where("app_id = ? AND role_id = ? AND name = ?", app.ID, role.ID, r).FirstOrCreate(&Access{
AppID: app.ID,
RoleID: &role.ID,
Name: r,
Level: l,
}).Error)
if rName == "admin" {
adminID = role.ID
}
}
}
if app.InitRoleID == nil {
logv.AssertError(cfg.DB().Model(app).Update("init_role_id", adminID).Error)
}
return nil
}

@ -5,6 +5,7 @@ type Role struct {
Name string `json:"name" methods:"post,*patch,*list" parse:"json"` Name string `json:"name" methods:"post,*patch,*list" parse:"json"`
Des string `json:"des" methods:"post,*patch" parse:"json"` Des string `json:"des" methods:"post,*patch" parse:"json"`
AppID string `json:"app_id" gorm:"index;type:varchar(32)" methods:"post,*patch" parse:"json"` AppID string `json:"app_id" gorm:"index;type:varchar(32)" methods:"post,*patch" parse:"json"`
App *App `json:"app" gorm:"foreignKey:ID;references:AppID"` App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
UserCount uint `json:"user_count"` UserCount uint `json:"user_count"`
Access []*Access `json:"-"`
} }

@ -3,8 +3,23 @@ package models
import "time" import "time"
type TokenSalt struct { type TokenSalt struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path"` Username string `json:"username" parse:"json"`
Typ *string `json:"typ" parse:"json"`
} }
type TokenPost struct {
UserID string `json:"user_id" gorm:"index;type:varchar(32)" parse:"json"`
// 两种获取token方式一种用token换取(应用登录)一种用密码加密code换(oa登录)
Token *string `json:"token" parse:"json"`
Salt *string `json:"salt" parse:"json"`
Code *string `json:"code" parse:"json"`
AppID *string `json:"app_id" gorm:"index;type:varchar(32)" parse:"json"`
ExpiredAt *time.Time `json:"expired_at" parse:"json"`
OverPerm *string `json:"over_perm" parse:"json"`
}
type TokenGet struct { type TokenGet struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@token_id"` ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@token_id"`
} }
@ -19,13 +34,6 @@ type TokenDelete struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@token_id"` ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@token_id"`
} }
type TokenPost struct {
UserID string `json:"user_id" gorm:"index;type:varchar(32)" parse:"json"`
AppID string `json:"app_id" gorm:"index;type:varchar(32)" parse:"json"`
ExpiredAt *time.Time `json:"expired_at" parse:"json"`
OverPerm *string `json:"over_perm" parse:"json"`
}
type TokenList struct { type TokenList struct {
UserID string `json:"user_id" gorm:"index;type:varchar(32)" parse:"json"` UserID string `json:"user_id" gorm:"index;type:varchar(32)" parse:"json"`
AppID string `json:"app_id" gorm:"index;type:varchar(32)" parse:"json"` AppID string `json:"app_id" gorm:"index;type:varchar(32)" parse:"json"`

@ -57,12 +57,14 @@ type UserRoleDelete struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"` ID string `json:"id" gorm:"primaryKey;type:varchar(32)" parse:"path@user_role_id"`
UserID string `json:"user_id" parse:"path"` UserID string `json:"user_id" parse:"path"`
RoleID string `json:"role_id" parse:"path"` RoleID string `json:"role_id" parse:"path"`
AppID string `json:"app_id" parse:"json"`
} }
type UserRolePost struct { type UserRolePost struct {
UserID string `json:"user_id" parse:"path"` UserID string `json:"user_id" parse:"path"`
RoleID string `json:"role_id" parse:"path"` RoleID string `json:"role_id" parse:"path"`
Status string `json:"status" parse:"json"` Status string `json:"status" parse:"json"`
AppID string `json:"app_id" parse:"json"`
} }
type UserRoleList struct { type UserRoleList struct {

@ -1,5 +1,12 @@
package models package models
import (
"gorm.io/gorm"
)
// salt for user user password gen aes code
// salt 32 hex / 16 byte / 128 bit
// code 64 hex / 32 byte / 256 bit
type User struct { type User struct {
BaseModel BaseModel
Username string `json:"username" gorm:"type:varchar(100);unique;default:not null" methods:"post,*patch,*list" parse:"json"` Username string `json:"username" gorm:"type:varchar(100);unique;default:not null" methods:"post,*patch,*list" parse:"json"`
@ -12,14 +19,23 @@ type User struct {
Status uint `json:"status" methods:"*patch,*list" parse:"json"` Status uint `json:"status" methods:"*patch,*list" parse:"json"`
Salt string `json:"-" gorm:"type:varchar(32)" methods:"post" parse:"json"` Salt string `json:"-" gorm:"type:varchar(32)" methods:"post" parse:"json"`
Code string `json:"-" gorm:"type:varchar(256)" methods:"post" parse:"json"` Code string `json:"-" gorm:"type:varchar(64)" methods:"post" parse:"json"`
} }
type UserRole struct { type UserRole struct {
BaseModel BaseModel
UserID string `json:"user_id" methods:"post,delete" parse:"path"` UserID string `json:"user_id" methods:"post,delete" parse:"json"`
User *User `json:"user"` User *User `json:"-" gorm:"foreignKey:UserID;references:ID"`
RoleID string `json:"role_id" methods:"post,delete" parse:"path"`
Role *Role `json:"role"` RoleID string `json:"role_id" methods:"post,delete" parse:"json"`
Role *Role `json:"-" gorm:"foreignKey:RoleID;references:ID"`
AppID string `json:"app_id" methods:"post,delete" parse:"json"`
App *App `json:"-" gorm:"foreignKey:AppID;references:ID"`
Status string `json:"status" methods:"post,*patch,*list" parse:"json"` Status string `json:"status" methods:"post,*patch,*list" parse:"json"`
} }
func (m *UserRole) AfterCreate(tx *gorm.DB) error {
return tx.Model(&Role{}).Where("id = ?", m.RoleID).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
}

Loading…
Cancel
Save