用户加密机制设计初步完成
This commit is contained in:
parent
cd7029c298
commit
82b64a4bb2
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"OneAuth/api/app"
|
||||
"OneAuth/api/role"
|
||||
"OneAuth/api/user"
|
||||
"OneAuth/api/wx"
|
||||
"github.com/veypi/OneBD"
|
||||
@ -18,5 +19,7 @@ func Router(r OneBD.Router) {
|
||||
user.Router(r.SubRouter("/user"))
|
||||
wx.Router(r.SubRouter("wx"))
|
||||
app.Router(r.SubRouter("app"))
|
||||
role.Router(r)
|
||||
|
||||
//message.Router(r.SubRouter("/message"))
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/libs/base"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/models"
|
||||
@ -26,14 +27,40 @@ type appHandler struct {
|
||||
|
||||
func (h *appHandler) Get() (interface{}, error) {
|
||||
id := h.Meta().Params("id")
|
||||
if id == "" {
|
||||
return nil, oerr.ApiArgsMissing
|
||||
}
|
||||
h.query = &models.App{}
|
||||
h.query.UUID = id
|
||||
err := cfg.DB().Where(h.query).First(h.query).Error
|
||||
isSelf := h.Meta().Query("is_self")
|
||||
if isSelf != "" {
|
||||
// 无权限可以获取本系统基本信息
|
||||
h.query.ID = cfg.CFG.APPID
|
||||
err := cfg.DB().Where(h.query).First(h.query).Error
|
||||
return h.query, err
|
||||
}
|
||||
err := h.ParsePayload(h.Meta())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.query, nil
|
||||
if !h.GetAuth(auth.APP, id).CanRead() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
if id != "" {
|
||||
h.query.UUID = id
|
||||
err := cfg.DB().Where(h.query).First(h.query).Error
|
||||
return h.query, err
|
||||
}
|
||||
// 注释代码为获取已经绑定的应用
|
||||
//user := &models.User{}
|
||||
//user.ID = h.Payload.ID
|
||||
//err := cfg.DB().Preload("Roles.Auths").Preload("Auths").Where(user).First(user).Error
|
||||
//if err != nil {
|
||||
// return nil, oerr.DBErr.Attach(err)
|
||||
//}
|
||||
//ids := make([]string, 0, 10)
|
||||
//for _, a := range user.GetAuths() {
|
||||
// if a.RID == auth.Login && a.Level.CanDo() {
|
||||
// ids = append(ids, a.RUID)
|
||||
// }
|
||||
//}
|
||||
list := make([]*models.App, 0, 10)
|
||||
err = cfg.DB().Find(&list).Error
|
||||
return list, err
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@ package role
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/libs/base"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/models"
|
||||
"github.com/veypi/OneBD"
|
||||
"github.com/veypi/OneBD/core"
|
||||
@ -17,6 +19,9 @@ type authHandler struct {
|
||||
}
|
||||
|
||||
func (h *authHandler) Get() (interface{}, error) {
|
||||
if !h.GetAuth(auth.Auth).CanRead() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
l := make([]*models.Auth, 0, 10)
|
||||
return &l, cfg.DB().Find(&l).Error
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package role
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/libs/base"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/models"
|
||||
@ -20,8 +21,9 @@ type roleHandler struct {
|
||||
|
||||
func (h *roleHandler) Get() (interface{}, error) {
|
||||
id := h.Meta().ParamsInt("id")
|
||||
aid := h.Meta().ParamsInt("aid")
|
||||
act := h.Meta().Params("action")
|
||||
if !h.GetAuth(auth.Role, h.Meta().Params("id")).CanRead() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
if id > 0 {
|
||||
role := &models.Role{}
|
||||
role.ID = uint(id)
|
||||
@ -29,21 +31,6 @@ func (h *roleHandler) Get() (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if aid <= 0 {
|
||||
return role, nil
|
||||
}
|
||||
if !h.CheckAuth("admin", "").CanDoAny() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
at := &models.RoleAuth{}
|
||||
at.RoleID = role.ID
|
||||
at.AuthID = uint(aid)
|
||||
defer models.SyncGlobalRoles()
|
||||
if act == "bind" {
|
||||
err = cfg.DB().Where(at).FirstOrCreate(at).Error
|
||||
} else if act == "unbind" {
|
||||
err = cfg.DB().Where(at).Delete(at).Error
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
roles := make([]*models.Role, 0, 10)
|
||||
@ -52,7 +39,7 @@ func (h *roleHandler) Get() (interface{}, error) {
|
||||
}
|
||||
|
||||
func (h *roleHandler) Post() (interface{}, error) {
|
||||
if !h.CheckAuth("role", "").CanCreate() {
|
||||
if !h.GetAuth(auth.Role).CanCreate() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
role := &models.Role{}
|
||||
@ -61,15 +48,14 @@ func (h *roleHandler) Post() (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
role.ID = 0
|
||||
if role.Category == 0 || role.Name == "" {
|
||||
if role.Name == "" {
|
||||
return nil, oerr.ApiArgsMissing
|
||||
}
|
||||
defer models.SyncGlobalRoles()
|
||||
return role, cfg.DB().Where(role).FirstOrCreate(role).Error
|
||||
}
|
||||
|
||||
func (h *roleHandler) Patch() (interface{}, error) {
|
||||
if !h.CheckAuth("role", "").CanUpdate() {
|
||||
if !h.GetAuth(auth.Role).CanUpdate() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
query := &struct {
|
||||
@ -120,7 +106,7 @@ func (h *roleHandler) Patch() (interface{}, error) {
|
||||
}
|
||||
|
||||
func (h *roleHandler) Delete() (interface{}, error) {
|
||||
if !h.CheckAuth("role").CanDelete() {
|
||||
if !h.GetAuth(auth.Role).CanDelete() {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
rid := h.Meta().ParamsInt("id")
|
||||
@ -133,6 +119,5 @@ func (h *roleHandler) Delete() (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer models.SyncGlobalRoles()
|
||||
return nil, cfg.DB().Delete(role).Error
|
||||
}
|
||||
|
||||
@ -8,6 +8,6 @@ import (
|
||||
func Router(r OneBD.Router) {
|
||||
r.Set("/role/", roleP, rfc.MethodGet, rfc.MethodPost)
|
||||
r.Set("/role/:id", roleP, rfc.MethodGet, rfc.MethodDelete, rfc.MethodPatch)
|
||||
r.Set("/role/:id/:action/:aid", roleP, rfc.MethodGet)
|
||||
r.Set("/role/:id/:action/:rid", roleP, rfc.MethodGet)
|
||||
r.Set("/auth/", authP, rfc.MethodGet)
|
||||
}
|
||||
|
||||
104
api/user/user.go
104
api/user/user.go
@ -2,9 +2,13 @@ package user
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/app"
|
||||
"OneAuth/libs/base"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/libs/token"
|
||||
"OneAuth/models"
|
||||
"errors"
|
||||
|
||||
//"OneAuth/ws"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
@ -68,10 +72,17 @@ func (h *handler) Get() (interface{}, error) {
|
||||
|
||||
// Post register user
|
||||
func (h *handler) Post() (interface{}, error) {
|
||||
if !cfg.CFG.EnableRegister {
|
||||
return nil, oerr.NoAuth.AttachStr("register disabled.")
|
||||
self := &models.App{}
|
||||
self.ID = cfg.CFG.APPID
|
||||
err := cfg.DB().Where(self).First(self).Error
|
||||
if err != nil {
|
||||
return nil, oerr.DBErr.Attach(err)
|
||||
}
|
||||
if !self.EnableRegister {
|
||||
return nil, oerr.NoAuth.AttachStr("register disabled")
|
||||
}
|
||||
var userdata = struct {
|
||||
UUID string `json:"uuid"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
@ -101,16 +112,40 @@ func (h *handler) Post() (interface{}, error) {
|
||||
h.User.Username = userdata.Username
|
||||
h.User.Email = userdata.Email
|
||||
h.User.Position = userdata.Position
|
||||
if err := h.User.UpdateAuth(string(pass)); err != nil {
|
||||
if err := h.User.UpdatePass(string(pass)); err != nil {
|
||||
log.HandlerErrs(err)
|
||||
return nil, oerr.ResourceCreatedFailed
|
||||
}
|
||||
tx := cfg.DB().Begin()
|
||||
if err := tx.Create(&h.User).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, oerr.ResourceDuplicated
|
||||
err = cfg.DB().Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&h.User).Error; err != nil {
|
||||
return oerr.ResourceDuplicated
|
||||
}
|
||||
err := app.AddUser(tx, self.ID, h.User.ID, self.InitRoleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if userdata.UUID != self.UUID && userdata.UUID != "" {
|
||||
target := &models.App{}
|
||||
target.UUID = userdata.UUID
|
||||
err = tx.Where(target).First(target).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if target.EnableRegister {
|
||||
err := app.AddUser(tx, target.ID, h.User.ID, target.InitRoleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tx.Commit()
|
||||
return h.User, nil
|
||||
}
|
||||
|
||||
@ -142,7 +177,7 @@ func (h *handler) Patch() (interface{}, error) {
|
||||
return nil, oerr.NoAuth
|
||||
}
|
||||
if len(opts.Password) >= 6 {
|
||||
if err := target.UpdateAuth(opts.Password); err != nil {
|
||||
if err := target.UpdatePass(opts.Password); err != nil {
|
||||
log.HandlerErrs(err)
|
||||
return nil, oerr.ApiArgsError.AttachStr(err.Error())
|
||||
}
|
||||
@ -187,9 +222,9 @@ func (h *handler) Head() (interface{}, error) {
|
||||
if len(uid) == 0 || len(password) == 0 {
|
||||
return nil, oerr.ApiArgsError
|
||||
}
|
||||
appID, err := strconv.Atoi(h.Meta().Query("app_id"))
|
||||
if err != nil || appID <= 0 {
|
||||
return nil, oerr.ApiArgsMissing
|
||||
appUUID := h.Meta().Query("uuid")
|
||||
if appUUID == "" {
|
||||
return nil, oerr.ApiArgsMissing.AttachStr("uuid")
|
||||
}
|
||||
h.User = new(models.User)
|
||||
uidType := h.Meta().Query("uid_type")
|
||||
@ -203,32 +238,15 @@ func (h *handler) Head() (interface{}, error) {
|
||||
default:
|
||||
h.User.Username = uid
|
||||
}
|
||||
app := &models.App{}
|
||||
app.ID = uint(appID)
|
||||
err = cfg.DB().Where(app).Find(app).Error
|
||||
target := &models.App{}
|
||||
target.UUID = appUUID
|
||||
err = cfg.DB().Where(target).Find(target).Error
|
||||
if err != nil {
|
||||
return nil, oerr.DBErr.Attach(err)
|
||||
}
|
||||
if err := cfg.DB().Preload("Roles").Where(h.User).First(h.User).Error; err != nil {
|
||||
if err := cfg.DB().Preload("Roles.Auths").Preload("Auths").Where(h.User).First(h.User).Error; err != nil {
|
||||
if err.Error() == gorm.ErrRecordNotFound.Error() {
|
||||
// admin 登录自动注册
|
||||
if h.User.Username == "admin" {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
h.User.Icon = fmt.Sprintf("/media/icon/default/%04d.jpg", r.Intn(230))
|
||||
err = h.User.UpdateAuth(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
role := &models.Role{}
|
||||
role.ID = 1
|
||||
h.User.Roles = []*models.Role{role}
|
||||
err = cfg.DB().Create(h.User).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, oerr.AccountNotExist
|
||||
}
|
||||
return nil, oerr.AccountNotExist
|
||||
} else {
|
||||
log.HandlerErrs(err)
|
||||
return nil, oerr.DBErr.Attach(err)
|
||||
@ -238,15 +256,27 @@ func (h *handler) Head() (interface{}, error) {
|
||||
if err != nil || !isAuth {
|
||||
return nil, oerr.PassError.Attach(err)
|
||||
}
|
||||
if h.User.Status == "disabled" {
|
||||
au := &models.AppUser{}
|
||||
au.UserID = h.User.ID
|
||||
au.AppID = target.ID
|
||||
err = cfg.DB().Where(au).First(au).Error
|
||||
appID := target.ID
|
||||
h.Meta().SetHeader("content", target.UserRefreshUrl)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
appID = cfg.CFG.APPID
|
||||
h.Meta().SetHeader("content", "/app/"+target.UUID)
|
||||
} else if au.Disabled {
|
||||
return nil, oerr.DisableLogin
|
||||
}
|
||||
token, err := h.User.GetToken(app.Key, app.ID)
|
||||
tokenStr, err := token.GetToken(h.User, appID)
|
||||
if err != nil {
|
||||
log.HandlerErrs(err)
|
||||
return nil, oerr.Unknown.Attach(err)
|
||||
}
|
||||
h.Meta().SetHeader("auth_token", token)
|
||||
h.Meta().SetHeader("auth_token", tokenStr)
|
||||
log.Info().Msg(h.User.Username + " login")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -35,9 +35,8 @@ func (h *userRoleHandler) Post() (interface{}, error) {
|
||||
err = cfg.DB().First(query, query.ID).Error
|
||||
} else if query.Name != "" {
|
||||
err = cfg.DB().Where(map[string]interface{}{
|
||||
"name": query.Name,
|
||||
"category": query.Category,
|
||||
"tag": query.Tag,
|
||||
"name": query.Name,
|
||||
"tag": query.Tag,
|
||||
}).First(query).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
err = cfg.DB().Create(query).Error
|
||||
|
||||
38
cfg/cfg.go
38
cfg/cfg.go
@ -8,19 +8,19 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Path = cmd.GetCfgPath("OneAuth", "oa")
|
||||
var Path = cmd.GetCfgPath("oa", "settings")
|
||||
|
||||
var CFG = &struct {
|
||||
AdminUser string
|
||||
Host string
|
||||
LoggerPath string
|
||||
LoggerLevel string
|
||||
Key string
|
||||
TimeFormat string
|
||||
Debug bool
|
||||
EXEDir string
|
||||
EnableRegister bool
|
||||
DB struct {
|
||||
AdminUser string
|
||||
Host string
|
||||
LoggerPath string
|
||||
LoggerLevel string
|
||||
APPID uint
|
||||
APPKey string
|
||||
TimeFormat string
|
||||
Debug bool
|
||||
EXEDir string
|
||||
DB struct {
|
||||
Type string
|
||||
Addr string
|
||||
User string
|
||||
@ -28,14 +28,14 @@ var CFG = &struct {
|
||||
DB string
|
||||
}
|
||||
}{
|
||||
AdminUser: "admin",
|
||||
Host: "0.0.0.0:4001",
|
||||
LoggerPath: "",
|
||||
LoggerLevel: "debug",
|
||||
TimeFormat: "2006/01/02 15:04:05",
|
||||
Debug: true,
|
||||
EXEDir: "./",
|
||||
EnableRegister: true,
|
||||
APPID: 1,
|
||||
AdminUser: "admin",
|
||||
Host: "0.0.0.0:4001",
|
||||
LoggerPath: "",
|
||||
LoggerLevel: "debug",
|
||||
TimeFormat: "2006/01/02 15:04:05",
|
||||
Debug: true,
|
||||
EXEDir: "./",
|
||||
DB: struct {
|
||||
Type string
|
||||
Addr string
|
||||
|
||||
48
libs/app/user.go
Normal file
48
libs/app/user.go
Normal file
@ -0,0 +1,48 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/models"
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func AddUser(tx *gorm.DB, appID uint, userID uint, roleID uint) error {
|
||||
au := &models.AppUser{}
|
||||
au.AppID = appID
|
||||
au.UserID = userID
|
||||
err := tx.Where(au).First(au).Error
|
||||
if err == nil {
|
||||
return oerr.ResourceDuplicated
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
err = tx.Create(au).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = auth.BindUserRole(tx, userID, roleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Model(&models.App{}).Where("id = ?", appID).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
|
||||
}
|
||||
return err
|
||||
}
|
||||
func EnableUser(tx *gorm.DB, appID uint, userID uint) error {
|
||||
au := &models.AppUser{}
|
||||
au.AppID = appID
|
||||
au.UserID = userID
|
||||
err := tx.Where(au).First(au).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Where(au).Update("disabled", false).Error
|
||||
}
|
||||
|
||||
func DisableUser(tx *gorm.DB, appID uint, userID uint) error {
|
||||
au := &models.AppUser{}
|
||||
au.AppID = appID
|
||||
au.UserID = userID
|
||||
return tx.Where(au).Update("disabled", true).Error
|
||||
}
|
||||
66
libs/auth/auth.go
Normal file
66
libs/auth/auth.go
Normal file
@ -0,0 +1,66 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"OneAuth/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 定义oa系统权限
|
||||
|
||||
type Resource = string
|
||||
|
||||
const (
|
||||
User Resource = "user"
|
||||
APP Resource = "app"
|
||||
Res Resource = "resource"
|
||||
Role Resource = "role"
|
||||
Auth Resource = "auth"
|
||||
)
|
||||
|
||||
func BindUserRole(tx *gorm.DB, userID uint, roleID uint) error {
|
||||
r := &models.Role{}
|
||||
r.ID = roleID
|
||||
err := tx.Where(r).First(r).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ur := &models.UserRole{}
|
||||
ur.RoleID = roleID
|
||||
if r.IsUnique {
|
||||
err = tx.Where(ur).Update("user_id", userID).Error
|
||||
} else {
|
||||
ur.UserID = userID
|
||||
err = tx.Where(ur).FirstOrCreate(ur).Error
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func BindUserAuth(tx *gorm.DB, userID uint, resID uint, level models.AuthLevel, ruid string) error {
|
||||
return bind(tx, userID, resID, level, ruid, false)
|
||||
}
|
||||
|
||||
func BindRoleAuth(tx *gorm.DB, roleID uint, resID uint, level models.AuthLevel, ruid string) error {
|
||||
return bind(tx, roleID, resID, level, ruid, true)
|
||||
}
|
||||
|
||||
func bind(tx *gorm.DB, id uint, resID uint, level models.AuthLevel, ruid string, isRole bool) error {
|
||||
r := &models.Resource{}
|
||||
r.ID = resID
|
||||
err := tx.Where(r).First(r).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
au := &models.Auth{
|
||||
AppID: r.AppID,
|
||||
ResourceID: resID,
|
||||
RID: r.Name,
|
||||
RUID: ruid,
|
||||
Level: level,
|
||||
}
|
||||
if isRole {
|
||||
au.RoleID = &id
|
||||
} else {
|
||||
au.UserID = &id
|
||||
}
|
||||
return tx.Where(au).FirstOrCreate(au).Error
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/libs/tools"
|
||||
"github.com/json-iterator/go"
|
||||
@ -17,7 +16,7 @@ var json = jsoniter.ConfigFastest
|
||||
|
||||
type ApiHandler struct {
|
||||
OneBD.BaseHandler
|
||||
auth.UserHandler
|
||||
UserHandler
|
||||
}
|
||||
|
||||
func (h *ApiHandler) Init(m OneBD.Meta) error {
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
package auth
|
||||
package base
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/oerr"
|
||||
"OneAuth/libs/token"
|
||||
"OneAuth/models"
|
||||
"github.com/veypi/OneBD"
|
||||
"github.com/veypi/OneBD/rfc"
|
||||
)
|
||||
|
||||
type UserHandler struct {
|
||||
Payload *models.PayLoad
|
||||
Payload *token.PayLoad
|
||||
ignoreMethod map[rfc.Method]bool
|
||||
}
|
||||
|
||||
@ -17,12 +17,16 @@ func (a *UserHandler) Init(m OneBD.Meta) error {
|
||||
if a.ignoreMethod != nil && a.ignoreMethod[m.Method()] {
|
||||
return nil
|
||||
}
|
||||
a.Payload = new(models.PayLoad)
|
||||
token := m.GetHeader("auth_token")
|
||||
if token == "" {
|
||||
return a.ParsePayload(m)
|
||||
}
|
||||
|
||||
func (a *UserHandler) ParsePayload(m OneBD.Meta) error {
|
||||
a.Payload = new(token.PayLoad)
|
||||
tokenStr := m.GetHeader("auth_token")
|
||||
if tokenStr == "" {
|
||||
return oerr.NotLogin
|
||||
}
|
||||
ok, err := models.ParseToken(token, cfg.CFG.Key, a.Payload)
|
||||
ok, err := token.ParseToken(tokenStr, a.Payload)
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
11
libs/key/app.go
Normal file
11
libs/key/app.go
Normal file
@ -0,0 +1,11 @@
|
||||
package key
|
||||
|
||||
import "OneAuth/cfg"
|
||||
|
||||
func App(id uint) string {
|
||||
if id == cfg.CFG.APPID {
|
||||
return cfg.CFG.APPKey
|
||||
}
|
||||
// TODO
|
||||
return ""
|
||||
}
|
||||
@ -1,24 +1,24 @@
|
||||
package auth
|
||||
package key
|
||||
|
||||
import (
|
||||
"OneAuth/models"
|
||||
"OneAuth/cfg"
|
||||
"github.com/veypi/utils"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var keyCache = sync.Map{}
|
||||
|
||||
func GetUserKey(uid uint, app *models.App) string {
|
||||
if app.ID == 1 {
|
||||
func User(uid uint, appID uint) string {
|
||||
if appID == cfg.CFG.APPID {
|
||||
key, _ := keyCache.LoadOrStore(uid, utils.RandSeq(16))
|
||||
return key.(string)
|
||||
return cfg.CFG.APPKey + key.(string)
|
||||
}
|
||||
// TODO: 获取其他应用user_key
|
||||
return ""
|
||||
}
|
||||
|
||||
func RefreshUserKey(uid uint, app *models.App) string {
|
||||
if app.ID == 1 {
|
||||
func RefreshUser(uid uint, appID uint) string {
|
||||
if appID == cfg.CFG.APPID {
|
||||
key := utils.RandSeq(16)
|
||||
keyCache.Store(uid, key)
|
||||
return key
|
||||
127
libs/token/user.go
Normal file
127
libs/token/user.go
Normal file
@ -0,0 +1,127 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"OneAuth/libs/key"
|
||||
"OneAuth/models"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
InvalidToken = errors.New("invalid token")
|
||||
ExpiredToken = errors.New("expired token")
|
||||
)
|
||||
|
||||
type simpleAuth struct {
|
||||
RID string `json:"rid"`
|
||||
// 具体某个资源的id
|
||||
RUID string `json:"ruid"`
|
||||
Level models.AuthLevel `json:"level"`
|
||||
}
|
||||
|
||||
// TODO:: roles 是否会造成token过大 ?
|
||||
type PayLoad struct {
|
||||
ID uint `json:"id"`
|
||||
AppID uint `json:"app_id"`
|
||||
Iat int64 `json:"iat"` //token time
|
||||
Exp int64 `json:"exp"`
|
||||
Auth map[uint]*simpleAuth `json:"auth"`
|
||||
}
|
||||
|
||||
// GetAuth resource_uuid 缺省或仅第一个有效 权限会被更高权限覆盖
|
||||
func (p *PayLoad) GetAuth(ResourceID string, ResourceUUID ...string) models.AuthLevel {
|
||||
res := models.AuthNone
|
||||
if p == nil || p.Auth == nil {
|
||||
return res
|
||||
}
|
||||
ruid := ""
|
||||
if len(ResourceUUID) > 0 {
|
||||
ruid = ResourceUUID[0]
|
||||
}
|
||||
for _, a := range p.Auth {
|
||||
if a.RID == ResourceID {
|
||||
if a.RUID != "" {
|
||||
if a.RUID == ruid {
|
||||
if a.Level > res {
|
||||
res = a.Level
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if a.Level > res {
|
||||
res = a.Level
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func GetToken(u *models.User, appID uint) (string, error) {
|
||||
header := map[string]string{
|
||||
"typ": "JWT",
|
||||
"alg": "HS256",
|
||||
}
|
||||
//header := "{\"typ\": \"JWT\", \"alg\": \"HS256\"}"
|
||||
now := time.Now().Unix()
|
||||
payload := PayLoad{
|
||||
ID: u.ID,
|
||||
AppID: appID,
|
||||
Iat: now,
|
||||
Exp: now + 60*60*24,
|
||||
Auth: map[uint]*simpleAuth{},
|
||||
}
|
||||
for _, a := range u.GetAuths() {
|
||||
if appID == a.AppID {
|
||||
payload.Auth[a.ID] = &simpleAuth{
|
||||
RID: a.RID,
|
||||
RUID: a.RUID,
|
||||
Level: a.Level,
|
||||
}
|
||||
}
|
||||
}
|
||||
a, err := json.Marshal(header)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
A := base64.StdEncoding.EncodeToString(a)
|
||||
B := base64.StdEncoding.EncodeToString(b)
|
||||
hmacCipher := hmac.New(sha256.New, []byte(key.User(payload.ID, payload.AppID)))
|
||||
hmacCipher.Write([]byte(A + "." + B))
|
||||
C := hmacCipher.Sum(nil)
|
||||
return A + "." + B + "." + base64.StdEncoding.EncodeToString(C), nil
|
||||
}
|
||||
|
||||
func ParseToken(token string, payload *PayLoad) (bool, error) {
|
||||
var A, B, C string
|
||||
if seqs := strings.Split(token, "."); len(seqs) == 3 {
|
||||
A, B, C = seqs[0], seqs[1], seqs[2]
|
||||
} else {
|
||||
return false, InvalidToken
|
||||
}
|
||||
tempPayload, err := base64.StdEncoding.DecodeString(B)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(tempPayload, payload); err != nil {
|
||||
return false, err
|
||||
}
|
||||
hmacCipher := hmac.New(sha256.New, []byte(key.User(payload.ID, payload.AppID)))
|
||||
hmacCipher.Write([]byte(A + "." + B))
|
||||
tempC := hmacCipher.Sum(nil)
|
||||
if !hmac.Equal([]byte(C), []byte(base64.StdEncoding.EncodeToString(tempC))) {
|
||||
return false, nil
|
||||
}
|
||||
if time.Now().Unix() > payload.Exp {
|
||||
return false, ExpiredToken
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
15
main.go
15
main.go
@ -35,10 +35,15 @@ func main() {
|
||||
Value: cfg.CFG.LoggerPath,
|
||||
Destination: &cfg.CFG.LoggerPath,
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "id",
|
||||
Value: cfg.CFG.APPID,
|
||||
Destination: &cfg.CFG.APPID,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "key",
|
||||
Value: cfg.CFG.Key,
|
||||
Destination: &cfg.CFG.Key,
|
||||
Value: cfg.CFG.APPKey,
|
||||
Destination: &cfg.CFG.APPKey,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "exe_dir",
|
||||
@ -52,7 +57,11 @@ func main() {
|
||||
},
|
||||
}
|
||||
app.Commands = []*cli.Command{
|
||||
&sub.Web,
|
||||
sub.Web,
|
||||
sub.App,
|
||||
sub.Role,
|
||||
sub.Resource,
|
||||
sub.Init,
|
||||
}
|
||||
srv, err := cmd.NewSrv(app, sub.RunWeb, cfg.CFG, cfg.Path)
|
||||
if err != nil {
|
||||
|
||||
@ -4,9 +4,20 @@ var AppKeys = map[string]string{}
|
||||
|
||||
type App struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
UUID string `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
UUID string `json:"uuid" gorm:"unique"`
|
||||
Des string `json:"des"`
|
||||
Creator uint `json:"creator"`
|
||||
UserCount uint `json:"user_count"`
|
||||
Users []*User `json:"users" gorm:"many2many:app_users;"`
|
||||
// 初始用户角色
|
||||
InitRoleID uint `json:"init_role_id"`
|
||||
InitRole *Role `json:"init_role"`
|
||||
// 是否在首页隐藏
|
||||
Hide bool `json:"hide"`
|
||||
// PubKey string `json:"pub_key"`
|
||||
// PrivateKey string `json:"private_key"`
|
||||
// 认证成功跳转链接
|
||||
Host string `json:"host"`
|
||||
// 加解密用户token (key+key2)
|
||||
@ -14,11 +25,13 @@ type App struct {
|
||||
// key oa发放给app 双方保存 针对app生成 每个应用有一个
|
||||
// key2 app发放给oa app保存 oa使用一次销毁 针对当个用户生成 每个用户有一个
|
||||
// 获取app用户加密秘钥key2
|
||||
// TODO
|
||||
UserRefreshUrl string `json:"user_refresh_url"`
|
||||
// app 校验用户token时使用
|
||||
Key string `json:"key"`
|
||||
// 是否允许用户注册
|
||||
EnableRegister string `json:"enable_register"`
|
||||
Key string `json:"-"`
|
||||
// 是否允许用户自主注册
|
||||
EnableRegister bool `json:"enable_register"`
|
||||
EnableUserKey bool `json:"enable_user_key"`
|
||||
EnableUser bool `json:"enable_user"`
|
||||
EnableWx bool `json:"enable_wx"`
|
||||
EnablePhone bool `json:"enable_phone"`
|
||||
@ -26,6 +39,14 @@ type App struct {
|
||||
Wx *Wechat `json:"wx" gorm:"foreignkey:AppID;references:ID"`
|
||||
}
|
||||
|
||||
type AppUser struct {
|
||||
BaseModel
|
||||
AppID uint `json:"app_id"`
|
||||
UserID uint `json:"user_id"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type Wechat struct {
|
||||
BaseModel
|
||||
AppID uint `json:"app_id"`
|
||||
|
||||
@ -8,19 +8,22 @@ type UserRole struct {
|
||||
|
||||
type Role struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
// 角色类型
|
||||
// 1: 系统定义角色 2: 用户自定义角色
|
||||
Category uint `json:"category" gorm:"default:1"`
|
||||
AppID uint `json:"app_id"`
|
||||
App *App `json:"app"`
|
||||
Name string `json:"name"`
|
||||
// 角色标签
|
||||
Tag string `json:"tag" gorm:"default:''"`
|
||||
Users []*User `json:"users" gorm:"many2many:user_role;"`
|
||||
Users []*User `json:"users" gorm:"many2many:user_roles;"`
|
||||
// 具体权限
|
||||
Auths []*Auth `json:"auths" gorm:"foreignkey:RoleID;references:ID"`
|
||||
IsUnique bool `json:"is_unique" gorm:"default:false"`
|
||||
}
|
||||
|
||||
// AuthLevel 权限等级
|
||||
// 对于操作类权限
|
||||
// 0 禁止执行
|
||||
// 1 允许执行
|
||||
// 对于资源类权限
|
||||
// 0 相当于没有
|
||||
// 1 有限读权限
|
||||
// 2 读权限
|
||||
@ -32,6 +35,7 @@ type AuthLevel uint
|
||||
|
||||
const (
|
||||
AuthNone AuthLevel = 0
|
||||
AuthDo AuthLevel = 1
|
||||
// AuthPart TODO: 临时权限
|
||||
AuthPart AuthLevel = 1
|
||||
AuthRead AuthLevel = 2
|
||||
@ -41,6 +45,14 @@ const (
|
||||
AuthAll AuthLevel = 6
|
||||
)
|
||||
|
||||
func (a AuthLevel) Upper(b AuthLevel) bool {
|
||||
return a > b
|
||||
}
|
||||
|
||||
func (a AuthLevel) CanDo() bool {
|
||||
return a > AuthNone
|
||||
}
|
||||
|
||||
func (a AuthLevel) CanRead() bool {
|
||||
return a >= AuthRead
|
||||
}
|
||||
@ -61,22 +73,33 @@ func (a AuthLevel) CanDoAny() bool {
|
||||
return a >= AuthAll
|
||||
}
|
||||
|
||||
// 资源权限
|
||||
|
||||
// Auth 资源权限
|
||||
type Auth struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
// 该权限作用的应用
|
||||
AppID uint `json:"app_id"`
|
||||
App *App `json:"app"`
|
||||
// 权限绑定只能绑定一个
|
||||
RoleID uint `json:"role_id"`
|
||||
UserID uint `json:"user_id"`
|
||||
RoleID *uint `json:"role_id" gorm:""`
|
||||
Role *Role `json:"role"`
|
||||
UserID *uint `json:"user_id"`
|
||||
User *User `json:"user"`
|
||||
// 资源id
|
||||
ResourceID uint `json:"resource_id" gorm:"not null"`
|
||||
Resource *Resource `json:"resource"`
|
||||
// resource_name 用于其他系统方便区分权限的名字
|
||||
RID string `json:"rid" gorm:""`
|
||||
// 具体某个资源的id
|
||||
RUID string `json:"ruid"`
|
||||
// 权限标签
|
||||
Tag string `json:"tag"`
|
||||
RUID string `json:"ruid"`
|
||||
Level AuthLevel `json:"level"`
|
||||
Des string `json:"des"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
BaseModel
|
||||
AppID uint `json:"app_id"`
|
||||
App *App `json:"app"`
|
||||
Name string `json:"name"`
|
||||
// 权限标签
|
||||
Tag string `json:"tag"`
|
||||
Des string `json:"des"`
|
||||
}
|
||||
|
||||
138
models/user.go
138
models/user.go
@ -1,14 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/veypi/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// User db user model
|
||||
@ -25,46 +18,45 @@ type User struct {
|
||||
Status string `json:"status"`
|
||||
|
||||
Icon string `json:"icon"`
|
||||
Roles []*Role `json:"roles" gorm:"many2many:user_role;"`
|
||||
Roles []*Role `json:"roles" gorm:"many2many:user_roles;"`
|
||||
Apps []*App `json:"apps" gorm:"many2many:app_users;"`
|
||||
Auths []*Auth `json:"auths" gorm:"foreignkey:UserID;references:ID"`
|
||||
}
|
||||
|
||||
type simpleAuth struct {
|
||||
RID string `json:"rid"`
|
||||
// 具体某个资源的id
|
||||
RUID string `json:"ruid"`
|
||||
Level AuthLevel `json:"level"`
|
||||
func (u *User) String() string {
|
||||
return u.Username + ":" + u.Nickname
|
||||
}
|
||||
|
||||
// TODO:: roles 是否会造成token过大 ?
|
||||
type PayLoad struct {
|
||||
ID uint `json:"id"`
|
||||
Iat int64 `json:"iat"` //token time
|
||||
Exp int64 `json:"exp"`
|
||||
Auth map[uint]*simpleAuth `json:"auth"`
|
||||
}
|
||||
|
||||
// GetAuth resource_uuid 缺省或仅第一个有效 权限会被更高权限覆盖
|
||||
func (p *PayLoad) GetAuth(ResourceID string, ResourceUUID ...string) AuthLevel {
|
||||
res := AuthNone
|
||||
if p == nil || p.Auth == nil {
|
||||
return res
|
||||
func (u *User) GetAuths() []*Auth {
|
||||
list := make([]*Auth, 0, 10)
|
||||
for _, r := range u.Roles {
|
||||
for _, a := range r.Auths {
|
||||
list = append(list, a)
|
||||
}
|
||||
}
|
||||
for _, a := range u.Auths {
|
||||
list = append(list, a)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (u *User) GetAuth(appID uint, ResourceID string, ResourceUUID ...string) AuthLevel {
|
||||
var res = AuthNone
|
||||
ruid := ""
|
||||
if len(ResourceUUID) > 0 {
|
||||
ruid = ResourceUUID[0]
|
||||
}
|
||||
for _, a := range p.Auth {
|
||||
if a.RID == ResourceID {
|
||||
for _, a := range u.GetAuths() {
|
||||
if a.RID == ResourceID && a.AppID == appID {
|
||||
if a.RUID != "" {
|
||||
if a.RUID == ruid {
|
||||
if a.Level > res {
|
||||
if a.Level.Upper(res) {
|
||||
res = a.Level
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if a.Level > res {
|
||||
} else if a.Level.Upper(res) {
|
||||
res = a.Level
|
||||
}
|
||||
}
|
||||
@ -72,91 +64,7 @@ func (p *PayLoad) GetAuth(ResourceID string, ResourceUUID ...string) AuthLevel {
|
||||
return res
|
||||
}
|
||||
|
||||
func (u *User) String() string {
|
||||
return u.Username + ":" + u.Nickname
|
||||
}
|
||||
|
||||
func (u *User) GetToken(key string, appID uint) (string, error) {
|
||||
header := map[string]string{
|
||||
"typ": "JWT",
|
||||
"alg": "HS256",
|
||||
}
|
||||
//header := "{\"typ\": \"JWT\", \"alg\": \"HS256\"}"
|
||||
now := time.Now().Unix()
|
||||
payload := PayLoad{
|
||||
ID: u.ID,
|
||||
Iat: now,
|
||||
Exp: now + 60*60*24,
|
||||
Auth: map[uint]*simpleAuth{},
|
||||
}
|
||||
for _, r := range u.Roles {
|
||||
for _, a := range r.Auths {
|
||||
if appID == a.AppID {
|
||||
payload.Auth[a.ID] = &simpleAuth{
|
||||
RID: a.RID,
|
||||
RUID: a.RUID,
|
||||
Level: a.Level,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, a := range u.Auths {
|
||||
if appID == a.AppID {
|
||||
payload.Auth[a.ID] = &simpleAuth{
|
||||
RID: a.RID,
|
||||
RUID: a.RUID,
|
||||
Level: a.Level,
|
||||
}
|
||||
}
|
||||
}
|
||||
a, err := json.Marshal(header)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
A := base64.StdEncoding.EncodeToString(a)
|
||||
B := base64.StdEncoding.EncodeToString(b)
|
||||
hmacCipher := hmac.New(sha256.New, []byte(key))
|
||||
hmacCipher.Write([]byte(A + "." + B))
|
||||
C := hmacCipher.Sum(nil)
|
||||
return A + "." + B + "." + base64.StdEncoding.EncodeToString(C), nil
|
||||
}
|
||||
|
||||
var (
|
||||
InvalidToken = errors.New("invalid token")
|
||||
ExpiredToken = errors.New("expired token")
|
||||
)
|
||||
|
||||
func ParseToken(token string, key string, payload *PayLoad) (bool, error) {
|
||||
var A, B, C string
|
||||
if seqs := strings.Split(token, "."); len(seqs) == 3 {
|
||||
A, B, C = seqs[0], seqs[1], seqs[2]
|
||||
} else {
|
||||
return false, InvalidToken
|
||||
}
|
||||
hmacCipher := hmac.New(sha256.New, []byte(key))
|
||||
hmacCipher.Write([]byte(A + "." + B))
|
||||
tempC := hmacCipher.Sum(nil)
|
||||
if !hmac.Equal([]byte(C), []byte(base64.StdEncoding.EncodeToString(tempC))) {
|
||||
return false, nil
|
||||
}
|
||||
tempPayload, err := base64.StdEncoding.DecodeString(B)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(tempPayload, payload); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if time.Now().Unix() > payload.Exp {
|
||||
return false, ExpiredToken
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (u *User) UpdateAuth(ps string) (err error) {
|
||||
func (u *User) UpdatePass(ps string) (err error) {
|
||||
u.RealCode = utils.RandSeq(32)
|
||||
u.CheckCode, err = utils.AesEncrypt(u.RealCode, []byte(ps))
|
||||
return err
|
||||
|
||||
@ -8,11 +8,13 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@veypi/one-icon": "^1.0.1",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"js-base64": "^3.6.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-class-component": "^7.2.3",
|
||||
"vue-m-message": "^3.1.0",
|
||||
"vue-property-decorator": "^9.1.2",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.4.0",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.6 KiB |
@ -1,19 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
dark
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<one-icon style="color: aqua;font-size: 56px">glassdoor</one-icon>
|
||||
<span class="font-italic font-weight-bold" style="font-size: 20px">统一认证</span>
|
||||
</div>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text class="font-italic" style="font-size: 20px">
|
||||
统一认证
|
||||
</v-btn>
|
||||
</v-app-bar>
|
||||
|
||||
<v-main>
|
||||
@ -32,8 +31,9 @@ export default Vue.extend({
|
||||
//
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
beforeCreate() {
|
||||
util.title('统一认证')
|
||||
this.$store.dispatch('fetchSelf')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -32,7 +32,7 @@ class Interface {
|
||||
const newFail = function (data: any) {
|
||||
if (data && data.code === 40001) {
|
||||
// no login
|
||||
store.dispatch('handleLogOut')
|
||||
store.dispatch('handleLogout')
|
||||
return
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
@ -52,7 +52,7 @@ class Interface {
|
||||
} else {
|
||||
newFail(data)
|
||||
if (data.code === 41001) {
|
||||
store.dispatch('handleLogOut')
|
||||
store.dispatch('handleLogout')
|
||||
// bus.$emit('log_out')
|
||||
}
|
||||
}
|
||||
@ -106,6 +106,9 @@ const role = {
|
||||
|
||||
const app = {
|
||||
local: '/api/app/',
|
||||
self() {
|
||||
return new Interface(ajax.get, this.local, {is_self: true})
|
||||
},
|
||||
get(id: string) {
|
||||
return new Interface(ajax.get, this.local + id)
|
||||
},
|
||||
@ -116,15 +119,18 @@ const app = {
|
||||
|
||||
const user = {
|
||||
local: '/api/user/',
|
||||
register(username: string, password: string, prop?: any) {
|
||||
register(username: string, password: string, uuid: string, prop?: any) {
|
||||
const data = Object.assign({
|
||||
username: username,
|
||||
uuid: uuid,
|
||||
password: Base64.encode(password)
|
||||
}, prop)
|
||||
return new Interface(ajax.post, this.local, data)
|
||||
},
|
||||
login(username: string, password: string) {
|
||||
login(username: string, password: string, uuid: string) {
|
||||
return new Interface(ajax.head, this.local + username, {
|
||||
uid_type: 'username',
|
||||
uuid: uuid,
|
||||
password: Base64.encode(password)
|
||||
})
|
||||
}
|
||||
@ -196,21 +202,6 @@ const api = {
|
||||
return new Interface(ajax.get, '/api/user/', {
|
||||
username
|
||||
})
|
||||
},
|
||||
login(username: string, password: string) {
|
||||
return new Interface(ajax.head, '/api/user/' + username, {
|
||||
password: Base64.encode(password)
|
||||
})
|
||||
},
|
||||
// @title 职位
|
||||
// @domain 部门
|
||||
register(username: string, password: string, domain?: string, title?: string) {
|
||||
return new Interface(ajax.post, '/api/user/', {
|
||||
username: username,
|
||||
password: Base64.encode(password),
|
||||
domain: domain,
|
||||
title: title
|
||||
})
|
||||
}
|
||||
},
|
||||
message: message
|
||||
|
||||
@ -9,7 +9,9 @@ import '@/libs/wwLogin.js'
|
||||
components: {}
|
||||
})
|
||||
export default class WxLogin extends Vue {
|
||||
goto(id: string, app: string, url: string, state?: string, href?: string) {
|
||||
goto(id: string, app: string, url: string, state?: number, href?: string) {
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
window.WwLogin({
|
||||
id: 'wx_reg',
|
||||
appid: id,
|
||||
@ -21,13 +23,13 @@ export default class WxLogin extends Vue {
|
||||
}
|
||||
|
||||
@Prop({default: ''})
|
||||
aid: ''
|
||||
aid = ''
|
||||
|
||||
@Prop({default: ''})
|
||||
app: ''
|
||||
app = ''
|
||||
|
||||
@Prop({default: ''})
|
||||
url: ''
|
||||
url = ''
|
||||
|
||||
mounted() {
|
||||
this.goto(this.aid, this.app, this.url, new Date().getTime())
|
||||
|
||||
28
oaf/src/components/one-icon/icon.vue
Normal file
28
oaf/src/components/one-icon/icon.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use :xlink:href="'#icon-'+icon"></use>
|
||||
</svg>
|
||||
</template>
|
||||
<script lang='ts'>
|
||||
import {Component, Vue} from 'vue-property-decorator'
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
})
|
||||
export default class OneIcon extends Vue {
|
||||
get icon() {
|
||||
if (this.$slots.default) return this.$slots.default[0].text?.trim()
|
||||
console.warn('blank icon name')
|
||||
return ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
26
oaf/src/components/one-icon/index.ts
Normal file
26
oaf/src/components/one-icon/index.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import Vue from 'vue'
|
||||
import OneIcon from './icon.vue'
|
||||
|
||||
function loadJS(url: string) {
|
||||
const script = document.createElement('script')
|
||||
script.type = 'text/javascript'
|
||||
script.src = url
|
||||
document.getElementsByTagName('head')[0].appendChild(script)
|
||||
}
|
||||
|
||||
export default {
|
||||
installed: false,
|
||||
install(vue: typeof Vue, options?: { href: '' }): void {
|
||||
if (this.installed) {
|
||||
return
|
||||
}
|
||||
this.installed = true
|
||||
if (options && options.href) {
|
||||
console.log(options.href)
|
||||
loadJS(options.href)
|
||||
} else {
|
||||
console.error('not set iconfont href')
|
||||
}
|
||||
vue.component('one-icon', OneIcon)
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,7 @@ function padLeftZero(str: string): string {
|
||||
|
||||
const util = {
|
||||
title: function (title: string) {
|
||||
window.document.title = title ? title + ' - Home' : 'veypi project'
|
||||
window.document.title = title ? title + ' - oa' : 'veypi project'
|
||||
},
|
||||
getCookie(name: string) {
|
||||
const reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
|
||||
|
||||
@ -4,7 +4,14 @@ import router from './router'
|
||||
import store from './store'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import {Api} from '@/api'
|
||||
import OneIcon from '@veypi/one-icon'
|
||||
import Message from 'vue-m-message'
|
||||
import 'vue-m-message/dist/index.css'
|
||||
|
||||
Vue.use(Message) // will mount `Vue.prototype.$message`
|
||||
|
||||
// Vue.use(OneIcon, {href: 'https://at.alicdn.com/t/font_2872366_7aws02sx9bl.js'})
|
||||
Vue.use(OneIcon, {href: './icon.js'})
|
||||
Vue.use(Api)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
@ -4,13 +4,23 @@ import Home from '../views/Home.vue'
|
||||
import Demo from '@/views/demo.vue'
|
||||
import Login from '@/views/login.vue'
|
||||
import Register from '@/views/register.vue'
|
||||
import NotFound from '@/views/404.vue'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
// 避免push到相同路径报错
|
||||
// 获取原型对象上的push函数
|
||||
const originalPush = VueRouter.prototype.push
|
||||
// 修改原型对象中的push方法
|
||||
VueRouter.prototype.push = function push(location: any) {
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
return originalPush.call(this, location).catch(err => err)
|
||||
}
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
name: 'home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
@ -19,12 +29,12 @@ const routes: Array<RouteConfig> = [
|
||||
component: Demo
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
path: '/login/:uuid?',
|
||||
name: 'login',
|
||||
component: Login
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
path: '/register/:uuid?',
|
||||
name: 'register',
|
||||
component: Register
|
||||
},
|
||||
@ -32,6 +42,11 @@ const routes: Array<RouteConfig> = [
|
||||
path: '/wx',
|
||||
name: 'wx',
|
||||
component: () => import('../views/wx.vue')
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
name: '404',
|
||||
component: NotFound
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@ -1,16 +1,30 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import api from '@/api'
|
||||
import router from '@/router'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
oauuid: '',
|
||||
user: null
|
||||
},
|
||||
mutations: {
|
||||
setOA(state: any, data: any) {
|
||||
state.oauuid = data.uuid
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchSelf({commit}) {
|
||||
api.app.self().Start(d => {
|
||||
commit('setOA', d)
|
||||
})
|
||||
},
|
||||
handleLogout() {
|
||||
localStorage.removeItem('auth_token')
|
||||
router.push({name: 'login'})
|
||||
}
|
||||
},
|
||||
modules: {
|
||||
}
|
||||
modules: {}
|
||||
})
|
||||
|
||||
24
oaf/src/views/404.vue
Normal file
24
oaf/src/views/404.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<style>
|
||||
</style>
|
||||
<template>
|
||||
<div class='home d-flex justify-center align-center'>
|
||||
<one-icon style="font-size: 100px">404</one-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import {Component, Vue} from 'vue-property-decorator'
|
||||
import util from '@/libs/util'
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
})
|
||||
export default class NotFound extends Vue {
|
||||
mounted() {
|
||||
}
|
||||
|
||||
created() {
|
||||
util.title('404')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -6,20 +6,38 @@
|
||||
</style>
|
||||
<template>
|
||||
<div class='home d-flex justify-center align-center'>
|
||||
<one-icon style="color: aqua;font-size: 50px">glassdoor</one-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import {Component, Vue} from 'vue-property-decorator'
|
||||
import util from '@/libs/util'
|
||||
|
||||
@Component({
|
||||
components: {}
|
||||
})
|
||||
export default class Home extends Vue {
|
||||
apps = []
|
||||
|
||||
getApps() {
|
||||
this.$api.app.list().Start(d => {
|
||||
console.log(d)
|
||||
this.apps = d
|
||||
})
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.getApps()
|
||||
}
|
||||
|
||||
created() {
|
||||
}
|
||||
|
||||
beforeCreate() {
|
||||
if (!util.checkLogin()) {
|
||||
this.$router.push({name: 'login', query: this.$route.query, params: this.$route.params})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -54,7 +54,8 @@
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
<v-btn type="primary" @click="handleSubmit">登录</v-btn>
|
||||
<router-link to="/register" style="text-decoration: none;">
|
||||
<router-link :to="{name: 'register', query:$route.query, params: $route.params}"
|
||||
style="text-decoration: none;">
|
||||
<v-btn type="primary" style="margin-left:8px">注册</v-btn>
|
||||
</router-link>
|
||||
</v-card-actions>
|
||||
@ -87,13 +88,26 @@ export default class Login extends Vue {
|
||||
]
|
||||
}
|
||||
|
||||
get app_uuid() {
|
||||
return this.$route.params.uuid || this.$store.state.oauuid
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
this.$api.auth.login(this.formInline.user, this.formInline.password).Start(
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
if (!this.$refs.form.validate()) {
|
||||
return
|
||||
}
|
||||
this.$api.user.login(this.formInline.user, this.formInline.password, this.app_uuid).Start(
|
||||
data => {
|
||||
console.log(data)
|
||||
if (util.checkLogin()) {
|
||||
// this.$message.success('登录成功')
|
||||
// EventBus.$emit('login', true)
|
||||
this.$nextTick(() => {
|
||||
if (this.$route.query.redirect) {
|
||||
window.location.href = this.$route.query.redirect as string
|
||||
}
|
||||
this.$router.push({name: 'home'})
|
||||
})
|
||||
} else {
|
||||
@ -105,12 +119,5 @@ export default class Login extends Vue {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
mounted() {
|
||||
}
|
||||
|
||||
created() {
|
||||
console.log(this.formInline)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -90,20 +90,26 @@ export default class Register extends Vue {
|
||||
]
|
||||
}
|
||||
|
||||
get app_uuid() {
|
||||
return this.$route.params.uuid || this.$store.state.oauuid
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
if (!this.$refs.form.validate()) {
|
||||
return
|
||||
}
|
||||
this.$api.user.register(this.form.username, this.form.passwd).Start(
|
||||
this.$api.user.register(this.form.username, this.form.passwd, this.app_uuid).Start(
|
||||
(data) => {
|
||||
// this.$message.success('注册成功!')
|
||||
this.$router.push({name: 'login'})
|
||||
this.$message.success('注册成功!')
|
||||
this.$router.push({name: 'login', params: this.$route.params, query: this.$route.query})
|
||||
},
|
||||
(data) => {
|
||||
if (data && data.code === '31011') {
|
||||
// this.$message.error('用户名重复')
|
||||
this.$message.error('用户名重复')
|
||||
} else {
|
||||
// this.$message.error('注册失败')
|
||||
this.$message.error('注册失败')
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -1155,6 +1155,16 @@
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@veypi/one-icon@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@veypi/one-icon/-/one-icon-1.0.1.tgz#138adbbcf0738ac40cad44552a20e211da8087c6"
|
||||
integrity sha512-VEjK/SRpGTYKaqXu6FAVUXZtQy4hdZ886OI2eoMqMfMnt1pPExr9Vjz2NQOL1DZgMGT3mwlQHJyR3iJdz/eE1w==
|
||||
dependencies:
|
||||
core-js "^3.6.5"
|
||||
vue "^2.6.11"
|
||||
vue-class-component "^7.2.3"
|
||||
vue-property-decorator "^9.1.2"
|
||||
|
||||
"@vue/babel-helper-vue-jsx-merge-props@^1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz?cache=0&sync_timestamp=1602853295839&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-jsx-merge-props%2Fdownload%2F%40vue%2Fbabel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81"
|
||||
@ -8876,6 +8886,11 @@ vue-loader@^15.9.2:
|
||||
vue-hot-reload-api "^2.3.0"
|
||||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-m-message@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-m-message/-/vue-m-message-3.1.0.tgz#8061720ac777b624fad95375594ea142c7d55dc7"
|
||||
integrity sha512-Mu9ykD7vrUFfhGWTbevHoX1JNTAkOl6X6jDzqVoF5eB9dQHG4jSLmKwlHMZLlnT45lwwSze6vuvi8q5dxCWLQw==
|
||||
|
||||
vue-property-decorator@^9.1.2:
|
||||
version "9.1.2"
|
||||
resolved "https://registry.npm.taobao.org/vue-property-decorator/download/vue-property-decorator-9.1.2.tgz#266a2eac61ba6527e2e68a6933cfb98fddab5457"
|
||||
|
||||
54
sub/app.go
Normal file
54
sub/app.go
Normal file
@ -0,0 +1,54 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/models"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/veypi/utils"
|
||||
"github.com/veypi/utils/log"
|
||||
)
|
||||
|
||||
var App = &cli.Command{
|
||||
Name: "app",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "list",
|
||||
Action: runAppList,
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Action: runAppCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func runAppList(c *cli.Context) error {
|
||||
list := make([]*models.App, 0, 10)
|
||||
err := cfg.DB().Find(&list).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, a := range list {
|
||||
log.Info().Msgf("%d: %s", a.ID, a.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAppCreate(c *cli.Context) error {
|
||||
app := &models.App{}
|
||||
app.Name = c.String("name")
|
||||
app.Key = utils.RandSeq(16)
|
||||
app.UUID = utils.RandSeq(8)
|
||||
err := cfg.DB().Create(app).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("app: %s\nuuid: %s\nkey: %s", app.Name, app.UUID, app.Key)
|
||||
return nil
|
||||
}
|
||||
131
sub/init.go
Normal file
131
sub/init.go
Normal file
@ -0,0 +1,131 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/libs/auth"
|
||||
"OneAuth/models"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/veypi/utils/cmd"
|
||||
"github.com/veypi/utils/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var Init = &cli.Command{
|
||||
Name: "init",
|
||||
Action: runInit,
|
||||
}
|
||||
|
||||
func runInit(c *cli.Context) error {
|
||||
return InitSystem()
|
||||
}
|
||||
|
||||
// 初始化项目
|
||||
|
||||
func InitSystem() error {
|
||||
db()
|
||||
self, err := selfApp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.CFG.APPID = self.ID
|
||||
cfg.CFG.APPKey = self.Key
|
||||
err = cmd.DumpCfg(cfg.Path, cfg.CFG)
|
||||
// TODO
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
err = role(self.InitRoleID == 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func db() {
|
||||
db := cfg.DB()
|
||||
log.HandlerErrs(
|
||||
db.SetupJoinTable(&models.User{}, "Roles", &models.UserRole{}),
|
||||
db.SetupJoinTable(&models.Role{}, "Users", &models.UserRole{}),
|
||||
db.SetupJoinTable(&models.User{}, "Apps", &models.AppUser{}),
|
||||
db.SetupJoinTable(&models.App{}, "Users", &models.AppUser{}),
|
||||
db.AutoMigrate(&models.User{}, &models.Role{}, &models.Auth{}, &models.App{}),
|
||||
)
|
||||
log.HandlerErrs(
|
||||
db.AutoMigrate(&models.Wechat{}, &models.Resource{}),
|
||||
)
|
||||
}
|
||||
|
||||
func selfApp() (*models.App, error) {
|
||||
self := &models.App{
|
||||
Name: "OA",
|
||||
Icon: "",
|
||||
UUID: "jU5Jo5hM",
|
||||
Des: "",
|
||||
Creator: 0,
|
||||
UserCount: 0,
|
||||
Hide: false,
|
||||
Host: "",
|
||||
UserRefreshUrl: "/",
|
||||
Key: "cB43wF94MLTksyBK",
|
||||
EnableRegister: true,
|
||||
EnableUserKey: true,
|
||||
EnableUser: true,
|
||||
EnableWx: false,
|
||||
EnablePhone: false,
|
||||
EnableEmail: false,
|
||||
Wx: nil,
|
||||
}
|
||||
return self, cfg.DB().Where("uuid = ?", self.UUID).FirstOrCreate(self).Error
|
||||
}
|
||||
|
||||
func role(reset_init_role bool) error {
|
||||
authMap := make(map[string]*models.Resource)
|
||||
n := []string{
|
||||
auth.APP,
|
||||
auth.User,
|
||||
auth.Res,
|
||||
auth.Auth,
|
||||
auth.Role,
|
||||
}
|
||||
var err error
|
||||
adminRole := &models.Role{
|
||||
AppID: cfg.CFG.APPID,
|
||||
Name: "admin",
|
||||
IsUnique: false,
|
||||
}
|
||||
err = cfg.DB().Where(adminRole).FirstOrCreate(adminRole).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, na := range n {
|
||||
a := &models.Resource{
|
||||
AppID: cfg.CFG.APPID,
|
||||
Name: na,
|
||||
Tag: "",
|
||||
Des: "",
|
||||
}
|
||||
err = cfg.DB().Where(a).FirstOrCreate(a).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authMap[na] = a
|
||||
err = auth.BindRoleAuth(cfg.DB(), adminRole.ID, a.ID, models.AuthAll, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
userRole := &models.Role{
|
||||
AppID: cfg.CFG.APPID,
|
||||
Name: "user",
|
||||
IsUnique: false,
|
||||
}
|
||||
err = cfg.DB().Where(userRole).FirstOrCreate(userRole).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = auth.BindRoleAuth(cfg.DB(), userRole.ID, authMap[auth.APP].ID, models.AuthRead, strconv.Itoa(int(cfg.CFG.APPID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if reset_init_role {
|
||||
return cfg.DB().Model(&models.App{}).Where("id = ?", cfg.CFG.APPID).Update("init_role_id", adminRole.ID).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
114
sub/role.go
Normal file
114
sub/role.go
Normal file
@ -0,0 +1,114 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/models"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/veypi/utils/log"
|
||||
)
|
||||
|
||||
var Role = &cli.Command{
|
||||
Name: "role",
|
||||
Usage: "",
|
||||
Description: "",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "list",
|
||||
Action: runRoleList,
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Action: runRoleCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.UintFlag{
|
||||
Name: "id",
|
||||
Usage: "app id",
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "role name",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Flags: []cli.Flag{},
|
||||
}
|
||||
|
||||
func runRoleList(c *cli.Context) error {
|
||||
roles := make([]*models.Role, 0, 10)
|
||||
err := cfg.DB().Find(&roles).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range roles {
|
||||
log.Info().Msgf("%d %s@%d", r.ID, r.Name, r.AppID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runRoleCreate(c *cli.Context) error {
|
||||
id := c.Uint("id")
|
||||
name := c.String("name")
|
||||
rl := &models.Role{}
|
||||
rl.AppID = id
|
||||
rl.Name = name
|
||||
err := cfg.DB().Where(rl).FirstOrCreate(rl).Error
|
||||
return err
|
||||
}
|
||||
|
||||
var Resource = &cli.Command{
|
||||
Name: "resource",
|
||||
Usage: "resource manual",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "list",
|
||||
Action: runResourceList,
|
||||
Flags: []cli.Flag{
|
||||
&cli.UintFlag{
|
||||
Name: "id",
|
||||
Usage: "app id",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Action: runResourceCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.UintFlag{
|
||||
Name: "id",
|
||||
Usage: "app id",
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "role name",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func runResourceList(c *cli.Context) error {
|
||||
query := &models.Resource{}
|
||||
query.AppID = c.Uint("id")
|
||||
l := make([]*models.Resource, 0, 10)
|
||||
err := cfg.DB().Where(query).Find(&l).Error
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, r := range l {
|
||||
log.Info().Msgf("%d: %s@%d", r.ID, r.Name, r.AppID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runResourceCreate(c *cli.Context) error {
|
||||
query := &models.Resource{}
|
||||
query.AppID = c.Uint("id")
|
||||
query.Name = c.String("name")
|
||||
err := cfg.DB().Where(query).FirstOrCreate(query).Error
|
||||
return err
|
||||
}
|
||||
17
sub/web.go
17
sub/web.go
@ -3,7 +3,6 @@ package sub
|
||||
import (
|
||||
"OneAuth/api"
|
||||
"OneAuth/cfg"
|
||||
"OneAuth/models"
|
||||
"embed"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/veypi/OneBD"
|
||||
@ -20,7 +19,7 @@ var staticFiles embed.FS
|
||||
//go:embed static/index.html
|
||||
var indexFile []byte
|
||||
|
||||
var Web = cli.Command{
|
||||
var Web = &cli.Command{
|
||||
Name: "web",
|
||||
Usage: "",
|
||||
Description: "oa 核心http服务",
|
||||
@ -29,7 +28,6 @@ var Web = cli.Command{
|
||||
}
|
||||
|
||||
func RunWeb(c *cli.Context) error {
|
||||
_ = runSyncDB(c)
|
||||
ll := log.InfoLevel
|
||||
if l, err := log.ParseLevel(cfg.CFG.LoggerLevel); err == nil {
|
||||
ll = l
|
||||
@ -70,16 +68,3 @@ func RunWeb(c *cli.Context) error {
|
||||
log.Info().Msg("\nRouting Table\n" + app.Router().String())
|
||||
return app.Run()
|
||||
}
|
||||
|
||||
func runSyncDB(*cli.Context) error {
|
||||
db := cfg.DB()
|
||||
log.HandlerErrs(
|
||||
db.SetupJoinTable(&models.User{}, "Roles", &models.UserRole{}),
|
||||
db.SetupJoinTable(&models.Role{}, "Users", &models.UserRole{}),
|
||||
db.AutoMigrate(&models.User{}, &models.Role{}, &models.Auth{}),
|
||||
)
|
||||
log.HandlerErrs(
|
||||
db.AutoMigrate(&models.App{}, &models.Wechat{}),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user