更新权限和用户模型
This commit is contained in:
parent
3d194e935d
commit
cd7029c298
@ -1,3 +1,7 @@
|
|||||||
# OneAuth
|
# OneAuth
|
||||||
|
|
||||||
统一验证服务
|
统一验证服务
|
||||||
|
|
||||||
|
## 用户验证思路
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@ -15,7 +15,7 @@ func Router(r OneBD.Router) {
|
|||||||
r.SetInternalErrorFunc(func(m core.Meta) {
|
r.SetInternalErrorFunc(func(m core.Meta) {
|
||||||
m.Write([]byte("{\"status\": 0}"))
|
m.Write([]byte("{\"status\": 0}"))
|
||||||
})
|
})
|
||||||
user.Router(r.SubRouter("/auth/user"))
|
user.Router(r.SubRouter("/user"))
|
||||||
wx.Router(r.SubRouter("wx"))
|
wx.Router(r.SubRouter("wx"))
|
||||||
app.Router(r.SubRouter("app"))
|
app.Router(r.SubRouter("app"))
|
||||||
//message.Router(r.SubRouter("/message"))
|
//message.Router(r.SubRouter("/message"))
|
||||||
|
|||||||
@ -31,7 +31,7 @@ func (h *appHandler) Get() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
h.query = &models.App{}
|
h.query = &models.App{}
|
||||||
h.query.UUID = id
|
h.query.UUID = id
|
||||||
err := cfg.DB().Where(h.query).Preload("Wx").First(h.query).Error
|
err := cfg.DB().Where(h.query).First(h.query).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import (
|
|||||||
func Router(r OneBD.Router) {
|
func Router(r OneBD.Router) {
|
||||||
pool := OneBD.NewHandlerPool(func() OneBD.Handler {
|
pool := OneBD.NewHandlerPool(func() OneBD.Handler {
|
||||||
h := &handler{}
|
h := &handler{}
|
||||||
h.Ignore(rfc.MethodHead)
|
h.Ignore(rfc.MethodHead, rfc.MethodPost)
|
||||||
return h
|
return h
|
||||||
})
|
})
|
||||||
r.Set("/", pool, rfc.MethodGet, rfc.MethodPost) // list
|
r.Set("/", pool, rfc.MethodGet, rfc.MethodPost) // list
|
||||||
@ -68,8 +68,8 @@ func (h *handler) Get() (interface{}, error) {
|
|||||||
|
|
||||||
// Post register user
|
// Post register user
|
||||||
func (h *handler) Post() (interface{}, error) {
|
func (h *handler) Post() (interface{}, error) {
|
||||||
if !h.CheckAuth("user").CanCreate() {
|
if !cfg.CFG.EnableRegister {
|
||||||
return nil, oerr.NoAuth
|
return nil, oerr.NoAuth.AttachStr("register disabled.")
|
||||||
}
|
}
|
||||||
var userdata = struct {
|
var userdata = struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@ -138,7 +138,7 @@ func (h *handler) Patch() (interface{}, error) {
|
|||||||
if err := cfg.DB().Where(&target).First(&target).Error; err != nil {
|
if err := cfg.DB().Where(&target).First(&target).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if target.ID != h.Payload.ID && !h.CheckAuth("admin").CanDoAny() {
|
if target.ID != h.Payload.ID {
|
||||||
return nil, oerr.NoAuth
|
return nil, oerr.NoAuth
|
||||||
}
|
}
|
||||||
if len(opts.Password) >= 6 {
|
if len(opts.Password) >= 6 {
|
||||||
@ -187,6 +187,10 @@ func (h *handler) Head() (interface{}, error) {
|
|||||||
if len(uid) == 0 || len(password) == 0 {
|
if len(uid) == 0 || len(password) == 0 {
|
||||||
return nil, oerr.ApiArgsError
|
return nil, oerr.ApiArgsError
|
||||||
}
|
}
|
||||||
|
appID, err := strconv.Atoi(h.Meta().Query("app_id"))
|
||||||
|
if err != nil || appID <= 0 {
|
||||||
|
return nil, oerr.ApiArgsMissing
|
||||||
|
}
|
||||||
h.User = new(models.User)
|
h.User = new(models.User)
|
||||||
uidType := h.Meta().Query("uid_type")
|
uidType := h.Meta().Query("uid_type")
|
||||||
switch uidType {
|
switch uidType {
|
||||||
@ -199,6 +203,12 @@ func (h *handler) Head() (interface{}, error) {
|
|||||||
default:
|
default:
|
||||||
h.User.Username = uid
|
h.User.Username = uid
|
||||||
}
|
}
|
||||||
|
app := &models.App{}
|
||||||
|
app.ID = uint(appID)
|
||||||
|
err = cfg.DB().Where(app).Find(app).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").Where(h.User).First(h.User).Error; err != nil {
|
||||||
if err.Error() == gorm.ErrRecordNotFound.Error() {
|
if err.Error() == gorm.ErrRecordNotFound.Error() {
|
||||||
// admin 登录自动注册
|
// admin 登录自动注册
|
||||||
@ -221,7 +231,7 @@ func (h *handler) Head() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.HandlerErrs(err)
|
log.HandlerErrs(err)
|
||||||
return nil, err
|
return nil, oerr.DBErr.Attach(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isAuth, err := h.User.CheckLogin(password)
|
isAuth, err := h.User.CheckLogin(password)
|
||||||
@ -231,7 +241,7 @@ func (h *handler) Head() (interface{}, error) {
|
|||||||
if h.User.Status == "disabled" {
|
if h.User.Status == "disabled" {
|
||||||
return nil, oerr.DisableLogin
|
return nil, oerr.DisableLogin
|
||||||
}
|
}
|
||||||
token, err := h.User.GetToken(cfg.CFG.Key)
|
token, err := h.User.GetToken(app.Key, app.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.HandlerErrs(err)
|
log.HandlerErrs(err)
|
||||||
return nil, oerr.Unknown.Attach(err)
|
return nil, oerr.Unknown.Attach(err)
|
||||||
|
|||||||
@ -19,7 +19,7 @@ type userRoleHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *userRoleHandler) Post() (interface{}, error) {
|
func (h *userRoleHandler) Post() (interface{}, error) {
|
||||||
if !h.CheckAuth("role").CanCreate() {
|
if !h.GetAuth("role").CanCreate() {
|
||||||
return nil, oerr.NoAuth
|
return nil, oerr.NoAuth
|
||||||
}
|
}
|
||||||
uid := h.Meta().ParamsInt("user_id")
|
uid := h.Meta().ParamsInt("user_id")
|
||||||
@ -67,7 +67,7 @@ func (h *userRoleHandler) Post() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *userRoleHandler) Delete() (interface{}, error) {
|
func (h *userRoleHandler) Delete() (interface{}, error) {
|
||||||
if !h.CheckAuth("role").CanDelete() {
|
if !h.GetAuth("role").CanDelete() {
|
||||||
return nil, oerr.NoAuth
|
return nil, oerr.NoAuth
|
||||||
}
|
}
|
||||||
uid := h.Meta().ParamsInt("user_id")
|
uid := h.Meta().ParamsInt("user_id")
|
||||||
|
|||||||
40
cfg/cfg.go
40
cfg/cfg.go
@ -11,15 +11,16 @@ import (
|
|||||||
var Path = cmd.GetCfgPath("OneAuth", "oa")
|
var Path = cmd.GetCfgPath("OneAuth", "oa")
|
||||||
|
|
||||||
var CFG = &struct {
|
var CFG = &struct {
|
||||||
AdminUser string
|
AdminUser string
|
||||||
Host string
|
Host string
|
||||||
LoggerPath string
|
LoggerPath string
|
||||||
LoggerLevel string
|
LoggerLevel string
|
||||||
Key string
|
Key string
|
||||||
TimeFormat string
|
TimeFormat string
|
||||||
Debug bool
|
Debug bool
|
||||||
EXEDir string
|
EXEDir string
|
||||||
DB struct {
|
EnableRegister bool
|
||||||
|
DB struct {
|
||||||
Type string
|
Type string
|
||||||
Addr string
|
Addr string
|
||||||
User string
|
User string
|
||||||
@ -27,13 +28,14 @@ var CFG = &struct {
|
|||||||
DB string
|
DB string
|
||||||
}
|
}
|
||||||
}{
|
}{
|
||||||
AdminUser: "admin",
|
AdminUser: "admin",
|
||||||
Host: "0.0.0.0:19528",
|
Host: "0.0.0.0:4001",
|
||||||
LoggerPath: "",
|
LoggerPath: "",
|
||||||
LoggerLevel: "debug",
|
LoggerLevel: "debug",
|
||||||
TimeFormat: "2006/01/02 15:04:05",
|
TimeFormat: "2006/01/02 15:04:05",
|
||||||
Debug: true,
|
Debug: true,
|
||||||
EXEDir: "./",
|
EXEDir: "./",
|
||||||
|
EnableRegister: true,
|
||||||
DB: struct {
|
DB: struct {
|
||||||
Type string
|
Type string
|
||||||
Addr string
|
Addr string
|
||||||
@ -41,9 +43,9 @@ var CFG = &struct {
|
|||||||
Pass string
|
Pass string
|
||||||
DB string
|
DB string
|
||||||
}{
|
}{
|
||||||
Type: "sqlite",
|
//Type: "sqlite",
|
||||||
//Addr: "127.0.0.1:3306",
|
Addr: "127.0.0.1:3306",
|
||||||
Addr: "oa.db",
|
//Addr: "oa.db",
|
||||||
User: "root",
|
User: "root",
|
||||||
Pass: "123456",
|
Pass: "123456",
|
||||||
DB: "one_auth",
|
DB: "one_auth",
|
||||||
|
|||||||
@ -8,12 +8,12 @@ import (
|
|||||||
"github.com/veypi/OneBD/rfc"
|
"github.com/veypi/OneBD/rfc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Auth struct {
|
type UserHandler struct {
|
||||||
Payload *models.PayLoad
|
Payload *models.PayLoad
|
||||||
ignoreMethod map[rfc.Method]bool
|
ignoreMethod map[rfc.Method]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) Init(m OneBD.Meta) error {
|
func (a *UserHandler) Init(m OneBD.Meta) error {
|
||||||
if a.ignoreMethod != nil && a.ignoreMethod[m.Method()] {
|
if a.ignoreMethod != nil && a.ignoreMethod[m.Method()] {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ func (a *Auth) Init(m OneBD.Meta) error {
|
|||||||
return oerr.NotLogin.Attach(err)
|
return oerr.NotLogin.Attach(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) Ignore(methods ...rfc.Method) {
|
func (a *UserHandler) Ignore(methods ...rfc.Method) {
|
||||||
if a.ignoreMethod == nil {
|
if a.ignoreMethod == nil {
|
||||||
a.ignoreMethod = make(map[rfc.Method]bool)
|
a.ignoreMethod = make(map[rfc.Method]bool)
|
||||||
}
|
}
|
||||||
@ -38,6 +38,6 @@ func (a *Auth) Ignore(methods ...rfc.Method) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) CheckAuth(name string, tags ...string) models.AuthLevel {
|
func (a *UserHandler) GetAuth(ResourceID string, ResourceUUID ...string) models.AuthLevel {
|
||||||
return a.Payload.CheckAuth(name, tags...)
|
return a.Payload.GetAuth(ResourceID, ResourceUUID...)
|
||||||
}
|
}
|
||||||
27
libs/auth/user_key.go
Normal file
27
libs/auth/user_key.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OneAuth/models"
|
||||||
|
"github.com/veypi/utils"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var keyCache = sync.Map{}
|
||||||
|
|
||||||
|
func GetUserKey(uid uint, app *models.App) string {
|
||||||
|
if app.ID == 1 {
|
||||||
|
key, _ := keyCache.LoadOrStore(uid, utils.RandSeq(16))
|
||||||
|
return key.(string)
|
||||||
|
}
|
||||||
|
// TODO: 获取其他应用user_key
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func RefreshUserKey(uid uint, app *models.App) string {
|
||||||
|
if app.ID == 1 {
|
||||||
|
key := utils.RandSeq(16)
|
||||||
|
keyCache.Store(uid, key)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@ -17,11 +17,11 @@ var json = jsoniter.ConfigFastest
|
|||||||
|
|
||||||
type ApiHandler struct {
|
type ApiHandler struct {
|
||||||
OneBD.BaseHandler
|
OneBD.BaseHandler
|
||||||
auth.Auth
|
auth.UserHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApiHandler) Init(m OneBD.Meta) error {
|
func (h *ApiHandler) Init(m OneBD.Meta) error {
|
||||||
return tools.MultiIniter(m, &h.BaseHandler, &h.Auth)
|
return tools.MultiIniter(m, &h.BaseHandler, &h.UserHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApiHandler) OnResponse(data interface{}) {
|
func (h *ApiHandler) OnResponse(data interface{}) {
|
||||||
|
|||||||
@ -1,16 +1,34 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
var AppKeys = map[string]string{}
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
UUID string `json:"uuid"`
|
Icon string `json:"icon"`
|
||||||
Host string `json:"host"`
|
UUID string `json:"uuid"`
|
||||||
WxID string `json:"wx_id" gorm:""`
|
// 认证成功跳转链接
|
||||||
Wx *Wechat `json:"wx" gorm:"association_foreignkey:ID"`
|
Host string `json:"host"`
|
||||||
|
// 加解密用户token (key+key2)
|
||||||
|
// 两个key都是请求获取时刷新
|
||||||
|
// key oa发放给app 双方保存 针对app生成 每个应用有一个
|
||||||
|
// key2 app发放给oa app保存 oa使用一次销毁 针对当个用户生成 每个用户有一个
|
||||||
|
// 获取app用户加密秘钥key2
|
||||||
|
UserRefreshUrl string `json:"user_refresh_url"`
|
||||||
|
// app 校验用户token时使用
|
||||||
|
Key string `json:"key"`
|
||||||
|
// 是否允许用户注册
|
||||||
|
EnableRegister string `json:"enable_register"`
|
||||||
|
EnableUser bool `json:"enable_user"`
|
||||||
|
EnableWx bool `json:"enable_wx"`
|
||||||
|
EnablePhone bool `json:"enable_phone"`
|
||||||
|
EnableEmail bool `json:"enable_email"`
|
||||||
|
Wx *Wechat `json:"wx" gorm:"foreignkey:AppID;references:ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Wechat struct {
|
type Wechat struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
AppID uint `json:"app_id"`
|
||||||
// 网页授权登录用
|
// 网页授权登录用
|
||||||
WxID string `json:"wx_id"`
|
WxID string `json:"wx_id"`
|
||||||
AgentID string `json:"agent_id"`
|
AgentID string `json:"agent_id"`
|
||||||
|
|||||||
@ -1,74 +1,44 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
|
||||||
"OneAuth/cfg"
|
|
||||||
"github.com/veypi/utils/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var GlobalRoles = make(map[uint]*Role)
|
|
||||||
|
|
||||||
func SyncGlobalRoles() {
|
|
||||||
roles := make([]*Role, 0, 10)
|
|
||||||
err := cfg.DB().Preload("Auths").Find(&roles).Error
|
|
||||||
if err != nil {
|
|
||||||
log.Warn().Msgf("sync global roles error: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, r := range roles {
|
|
||||||
GlobalRoles[r.ID] = r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserRole struct {
|
type UserRole struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
UserID uint `json:"user_id"`
|
UserID uint `json:"user_id"`
|
||||||
RoleID uint `json:"role_id"`
|
RoleID uint `json:"role_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RoleAuth struct {
|
|
||||||
BaseModel
|
|
||||||
RoleID uint `json:"role_id"`
|
|
||||||
AuthID uint `json:"auth_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Role struct {
|
type Role struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
// 角色类型
|
// 角色类型
|
||||||
// 0: 系统角色 1: 用户角色
|
// 1: 系统定义角色 2: 用户自定义角色
|
||||||
Category uint `json:"category" gorm:"default:0"`
|
Category uint `json:"category" gorm:"default:1"`
|
||||||
// 角色标签
|
// 角色标签
|
||||||
Tag string `json:"tag" gorm:"default:''"`
|
Tag string `json:"tag" gorm:"default:''"`
|
||||||
Users []*User `json:"users" gorm:"many2many:user_role;"`
|
Users []*User `json:"users" gorm:"many2many:user_role;"`
|
||||||
// 具体权限
|
// 具体权限
|
||||||
Auths []*Auth `json:"auths" gorm:"many2many:role_auth;"`
|
Auths []*Auth `json:"auths" gorm:"foreignkey:RoleID;references:ID"`
|
||||||
IsUnique bool `json:"is_unique" gorm:"default:false"`
|
IsUnique bool `json:"is_unique" gorm:"default:false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Role) CheckAuth(name string, tags ...string) AuthLevel {
|
// AuthLevel 权限等级
|
||||||
res := AuthNone
|
// 0 相当于没有
|
||||||
tag := ""
|
// 1 有限读权限
|
||||||
if len(tags) > 0 {
|
// 2 读权限
|
||||||
tag = tags[0]
|
// 3 创建权限
|
||||||
}
|
// 4 修改权限
|
||||||
for _, a := range r.Auths {
|
// 5 删除权限
|
||||||
if a.Name == "admin" && a.Tag == "" || (a.Name == "admin" && a.Tag == tag) || (a.Name == name && a.Tag == tag) {
|
// 6 赋予其余人权限
|
||||||
if a.Level > res {
|
|
||||||
res = a.Level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthLevel uint
|
type AuthLevel uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AuthNone AuthLevel = 0
|
AuthNone AuthLevel = 0
|
||||||
AuthRead AuthLevel = 1
|
// AuthPart TODO: 临时权限
|
||||||
AuthCreate AuthLevel = 2
|
AuthPart AuthLevel = 1
|
||||||
AuthUpdate AuthLevel = 3
|
AuthRead AuthLevel = 2
|
||||||
AuthDelete AuthLevel = 4
|
AuthCreate AuthLevel = 3
|
||||||
|
AuthUpdate AuthLevel = 4
|
||||||
|
AuthDelete AuthLevel = 5
|
||||||
|
AuthAll AuthLevel = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a AuthLevel) CanRead() bool {
|
func (a AuthLevel) CanRead() bool {
|
||||||
@ -88,17 +58,25 @@ func (a AuthLevel) CanDelete() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a AuthLevel) CanDoAny() bool {
|
func (a AuthLevel) CanDoAny() bool {
|
||||||
return a >= AuthDelete
|
return a >= AuthAll
|
||||||
}
|
}
|
||||||
|
|
||||||
// 资源权限
|
// 资源权限
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
AppID uint `json:"app_id"`
|
// 该权限作用的应用
|
||||||
|
AppID uint `json:"app_id"`
|
||||||
|
// 权限绑定只能绑定一个
|
||||||
|
RoleID uint `json:"role_id"`
|
||||||
|
UserID uint `json:"user_id"`
|
||||||
|
// 资源id
|
||||||
|
RID string `json:"rid" gorm:""`
|
||||||
|
// 具体某个资源的id
|
||||||
|
RUID string `json:"ruid"`
|
||||||
// 权限标签
|
// 权限标签
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
// 权限等级 0 相当于没有 1 读权限 2 创建权限 3 修改权限 4 删除权限
|
|
||||||
Level AuthLevel `json:"level"`
|
Level AuthLevel `json:"level"`
|
||||||
|
Des string `json:"des"`
|
||||||
}
|
}
|
||||||
|
|||||||
101
models/user.go
101
models/user.go
@ -7,7 +7,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/veypi/utils"
|
"github.com/veypi/utils"
|
||||||
"github.com/veypi/utils/log"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -27,33 +26,47 @@ type User struct {
|
|||||||
|
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
Roles []*Role `json:"roles" gorm:"many2many:user_role;"`
|
Roles []*Role `json:"roles" gorm:"many2many:user_role;"`
|
||||||
|
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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:: roles 是否会造成token过大 ?
|
// TODO:: roles 是否会造成token过大 ?
|
||||||
type PayLoad struct {
|
type PayLoad struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Username string `json:"username"`
|
Iat int64 `json:"iat"` //token time
|
||||||
Nickname string `json:"nickname"`
|
Exp int64 `json:"exp"`
|
||||||
Icon string `json:"icon"`
|
Auth map[uint]*simpleAuth `json:"auth"`
|
||||||
Iat int64 `json:"iat"` //token time
|
|
||||||
Exp int64 `json:"exp"`
|
|
||||||
Roles []uint `json:"roles"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PayLoad) CheckAuth(name string, tags ...string) AuthLevel {
|
// GetAuth resource_uuid 缺省或仅第一个有效 权限会被更高权限覆盖
|
||||||
|
func (p *PayLoad) GetAuth(ResourceID string, ResourceUUID ...string) AuthLevel {
|
||||||
res := AuthNone
|
res := AuthNone
|
||||||
if p == nil || p.Roles == nil {
|
if p == nil || p.Auth == nil {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
for _, id := range p.Roles {
|
ruid := ""
|
||||||
r := GlobalRoles[id]
|
if len(ResourceUUID) > 0 {
|
||||||
if r == nil {
|
ruid = ResourceUUID[0]
|
||||||
log.Warn().Msgf("not found role id: %d", id)
|
}
|
||||||
continue
|
for _, a := range p.Auth {
|
||||||
}
|
if a.RID == ResourceID {
|
||||||
t := r.CheckAuth(name, tags...)
|
if a.RUID != "" {
|
||||||
if t > res {
|
if a.RUID == ruid {
|
||||||
res = t
|
if a.Level > res {
|
||||||
|
res = a.Level
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if a.Level > res {
|
||||||
|
res = a.Level
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@ -63,26 +76,7 @@ func (u *User) String() string {
|
|||||||
return u.Username + ":" + u.Nickname
|
return u.Username + ":" + u.Nickname
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) CheckAuth(name string, tags ...string) AuthLevel {
|
func (u *User) GetToken(key string, appID uint) (string, error) {
|
||||||
res := AuthNone
|
|
||||||
if u == nil || u.Roles == nil {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
for _, t := range u.Roles {
|
|
||||||
r := GlobalRoles[t.ID]
|
|
||||||
if r == nil {
|
|
||||||
log.Warn().Msgf("not found role id: %d", t.ID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t := r.CheckAuth(name, tags...)
|
|
||||||
if t > res {
|
|
||||||
res = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *User) GetToken(key string) (string, error) {
|
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
"typ": "JWT",
|
"typ": "JWT",
|
||||||
"alg": "HS256",
|
"alg": "HS256",
|
||||||
@ -90,15 +84,30 @@ func (u *User) GetToken(key string) (string, error) {
|
|||||||
//header := "{\"typ\": \"JWT\", \"alg\": \"HS256\"}"
|
//header := "{\"typ\": \"JWT\", \"alg\": \"HS256\"}"
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
payload := PayLoad{
|
payload := PayLoad{
|
||||||
ID: u.ID,
|
ID: u.ID,
|
||||||
Username: u.Username,
|
Iat: now,
|
||||||
Nickname: u.Nickname,
|
Exp: now + 60*60*24,
|
||||||
Icon: u.Icon,
|
Auth: map[uint]*simpleAuth{},
|
||||||
Iat: now,
|
|
||||||
Exp: now + 60*60*24,
|
|
||||||
}
|
}
|
||||||
for _, r := range u.Roles {
|
for _, r := range u.Roles {
|
||||||
payload.Roles = append(payload.Roles, r.ID)
|
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)
|
a, err := json.Marshal(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<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://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">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import util from '@/libs/util'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
@ -32,7 +33,7 @@ export default Vue.extend({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.title = '统一认证'
|
util.title('统一认证')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -4,10 +4,14 @@
|
|||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Vue from 'vue'
|
||||||
import {Base64} from 'js-base64'
|
import {Base64} from 'js-base64'
|
||||||
import ajax from './ajax'
|
import ajax from './ajax'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
|
export type SuccessFunction<T> = (e: any) => void;
|
||||||
|
export type FailedFunction<T> = (e: any) => void;
|
||||||
|
|
||||||
const Code = {
|
const Code = {
|
||||||
42011: '无操作权限',
|
42011: '无操作权限',
|
||||||
22031: '资源不存在 或 您无权操作该资源'
|
22031: '资源不存在 或 您无权操作该资源'
|
||||||
@ -24,15 +28,16 @@ class Interface {
|
|||||||
this.data = data
|
this.data = data
|
||||||
}
|
}
|
||||||
|
|
||||||
Start(success: Function, fail?: Function) {
|
Start(success: SuccessFunction<any>, fail?: FailedFunction<any>) {
|
||||||
const newFail = function (data: any) {
|
const newFail = function (data: any) {
|
||||||
if (data && data.code === 40001) {
|
if (data && data.code === 40001) {
|
||||||
// no login
|
// no login
|
||||||
store.dispatch('handleLogOut')
|
store.dispatch('handleLogOut')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||||
|
// @ts-ignore
|
||||||
if (data && data.code > 0 && Code[data.code]) {
|
if (data && data.code > 0 && Code[data.code]) {
|
||||||
// Message.warning({message: Code[data.code] || data.err, offset: 100})
|
|
||||||
}
|
}
|
||||||
if (fail) {
|
if (fail) {
|
||||||
fail(data)
|
fail(data)
|
||||||
@ -103,12 +108,32 @@ const app = {
|
|||||||
local: '/api/app/',
|
local: '/api/app/',
|
||||||
get(id: string) {
|
get(id: string) {
|
||||||
return new Interface(ajax.get, this.local + id)
|
return new Interface(ajax.get, this.local + id)
|
||||||
|
},
|
||||||
|
list() {
|
||||||
|
return new Interface(ajax.get, this.local)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
local: '/api/user/',
|
||||||
|
register(username: string, password: string, prop?: any) {
|
||||||
|
const data = Object.assign({
|
||||||
|
username: username,
|
||||||
|
password: Base64.encode(password)
|
||||||
|
}, prop)
|
||||||
|
return new Interface(ajax.post, this.local, data)
|
||||||
|
},
|
||||||
|
login(username: string, password: string) {
|
||||||
|
return new Interface(ajax.head, this.local + username, {
|
||||||
|
password: Base64.encode(password)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
role: role,
|
role: role,
|
||||||
app: app,
|
app: app,
|
||||||
|
user: user,
|
||||||
admin: {
|
admin: {
|
||||||
auths() {
|
auths() {
|
||||||
return new Interface(ajax.get, '/api/auth/')
|
return new Interface(ajax.get, '/api/auth/')
|
||||||
@ -192,8 +217,8 @@ const api = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Api = {
|
const Api = {
|
||||||
install(Vue: any) {
|
install(vue: typeof Vue): void {
|
||||||
Vue.prototype.api = api
|
vue.prototype.$api = api
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export {Api}
|
export {Api}
|
||||||
|
|||||||
64
oaf/src/libs/util.ts
Normal file
64
oaf/src/libs/util.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
function padLeftZero(str: string): string {
|
||||||
|
return ('00' + str).substr(str.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
const util = {
|
||||||
|
title: function (title: string) {
|
||||||
|
window.document.title = title ? title + ' - Home' : 'veypi project'
|
||||||
|
},
|
||||||
|
getCookie(name: string) {
|
||||||
|
const reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
|
||||||
|
const arr = document.cookie.match(reg)
|
||||||
|
if (arr) {
|
||||||
|
return unescape(arr[2])
|
||||||
|
} else return null
|
||||||
|
},
|
||||||
|
delCookie(name: string) {
|
||||||
|
const exp = new Date()
|
||||||
|
exp.setTime(exp.getTime() - 1)
|
||||||
|
const cval = this.getCookie(name)
|
||||||
|
if (cval !== null) {
|
||||||
|
document.cookie = name + '=' + cval + ';expires=' + exp.toLocaleString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setCookie(name: string, value: string, time: number) {
|
||||||
|
const exp = new Date()
|
||||||
|
exp.setTime(exp.getTime() + time)
|
||||||
|
document.cookie =
|
||||||
|
name + '=' + escape(value) + ';expires=' + exp.toLocaleString()
|
||||||
|
},
|
||||||
|
checkLogin() {
|
||||||
|
// return parseInt(this.getCookie('stat')) === 1
|
||||||
|
return Boolean(localStorage.auth_token)
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDate(date: Date, fmt: string) {
|
||||||
|
if (/(y+)/.test(fmt)) {
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
(date.getFullYear() + '').substr(4 - RegExp.$1.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const o = {
|
||||||
|
'M+': date.getMonth() + 1,
|
||||||
|
'd+': date.getDate(),
|
||||||
|
'h+': date.getHours(),
|
||||||
|
'm+': date.getMinutes(),
|
||||||
|
's+': date.getSeconds()
|
||||||
|
}
|
||||||
|
for (const k in o) {
|
||||||
|
if (new RegExp(`(${k})`).test(fmt)) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||||
|
// @ts-ignore
|
||||||
|
const str = o[k] + ''
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
RegExp.$1.length === 1 ? str : padLeftZero(str)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default util
|
||||||
@ -1,6 +1,9 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import VueRouter, {RouteConfig} from 'vue-router'
|
import VueRouter, {RouteConfig} from 'vue-router'
|
||||||
import Home from '../views/Home.vue'
|
import Home from '../views/Home.vue'
|
||||||
|
import Demo from '@/views/demo.vue'
|
||||||
|
import Login from '@/views/login.vue'
|
||||||
|
import Register from '@/views/register.vue'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -11,12 +14,19 @@ const routes: Array<RouteConfig> = [
|
|||||||
component: Home
|
component: Home
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/app',
|
||||||
name: 'About',
|
name: 'app',
|
||||||
// route level code-splitting
|
component: Demo
|
||||||
// this generates a separate chunk (about.[hash].js) for this route
|
},
|
||||||
// which is lazy-loaded when the route is visited.
|
{
|
||||||
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
|
path: '/login',
|
||||||
|
name: 'login',
|
||||||
|
component: Login
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/register',
|
||||||
|
name: 'register',
|
||||||
|
component: Register
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/wx',
|
path: '/wx',
|
||||||
|
|||||||
1
oaf/src/shims-vue.d.ts
vendored
1
oaf/src/shims-vue.d.ts
vendored
@ -1,3 +1,4 @@
|
|||||||
|
declare module '*.js'
|
||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
export default Vue
|
export default Vue
|
||||||
|
|||||||
@ -5,6 +5,7 @@ Vue.use(Vuex)
|
|||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
|
user: null
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
},
|
},
|
||||||
|
|||||||
14
oaf/src/types/vue-prototype.d.ts
vendored
Normal file
14
oaf/src/types/vue-prototype.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// 1. 确保在声明补充的类型之前导入 'vue'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import api from '@/api'
|
||||||
|
|
||||||
|
export type PluginFunction<T> = (Vue: typeof Vue, options?: T) => void;
|
||||||
|
|
||||||
|
// 2. 定制一个文件,设置你想要补充的类型
|
||||||
|
// 在 types/vue.d.ts 里 Vue 有构造函数类型
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
// 3. 声明为 Vue 补充的东西
|
||||||
|
interface Vue {
|
||||||
|
$api: typeof api;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="about">
|
|
||||||
<h1>This is an about page</h1>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
21
oaf/src/views/demo.vue
Normal file
21
oaf/src/views/demo.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<div class='home d-flex justify-center align-center'>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Vue} from 'vue-property-decorator'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {}
|
||||||
|
})
|
||||||
|
export default class Demo extends Vue {
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
created() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
116
oaf/src/views/login.vue
Normal file
116
oaf/src/views/login.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<v-row align="center" class="fill-height" justify="center" style="background: #ebebeb">
|
||||||
|
<v-col cols="12" sm="8" md="6" lg="4" xl="3">
|
||||||
|
<v-card class="elevation-12 mx-5" style="opacity: 0.8">
|
||||||
|
<v-row justify="center">
|
||||||
|
<v-col cols="10">
|
||||||
|
<v-card class="elevation-1 mt-n12 primary theme--dark">
|
||||||
|
<v-card-text class="text-center">
|
||||||
|
<h1 class="display-2 font-weight-bold mb-2">Login</h1>
|
||||||
|
<v-tooltip left>
|
||||||
|
<template v-slot:activator="{ on }">
|
||||||
|
<v-btn icon large v-on="on">
|
||||||
|
<v-icon>mdi-cellphone</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<span style="font-family:'Noto Sans Armenian'">手机登录</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-tooltip right>
|
||||||
|
<template v-slot:activator="{ on }">
|
||||||
|
<v-btn icon large v-on="on">
|
||||||
|
<v-icon>mdi-barcode</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<span>授权码登录</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-card-text>
|
||||||
|
<v-form ref="form">
|
||||||
|
<v-text-field
|
||||||
|
v-model="formInline.user"
|
||||||
|
:counter="16"
|
||||||
|
:rules="ruleInline.user"
|
||||||
|
label="账号"
|
||||||
|
required
|
||||||
|
prepend-inner-icon="mdi-account-circle"
|
||||||
|
></v-text-field>
|
||||||
|
<v-text-field
|
||||||
|
v-model="formInline.password"
|
||||||
|
type="password"
|
||||||
|
:counter="16"
|
||||||
|
:rules="ruleInline.password"
|
||||||
|
label="密码"
|
||||||
|
prepend-inner-icon="mdi-lock"
|
||||||
|
@keyup.enter="handleSubmit"
|
||||||
|
required
|
||||||
|
></v-text-field>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer/>
|
||||||
|
<v-btn type="primary" @click="handleSubmit">登录</v-btn>
|
||||||
|
<router-link to="/register" style="text-decoration: none;">
|
||||||
|
<v-btn type="primary" style="margin-left:8px">注册</v-btn>
|
||||||
|
</router-link>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Vue} from 'vue-property-decorator'
|
||||||
|
import util from '@/libs/util'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {}
|
||||||
|
})
|
||||||
|
export default class Login extends Vue {
|
||||||
|
formInline = {
|
||||||
|
user: '',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleInline = {
|
||||||
|
user: [
|
||||||
|
(v: string) => !!v || 'required',
|
||||||
|
(v: string) => (v && v.length >= 3 && v.length <= 16) || '长度要求3~16'
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
(v: string) => !!v || 'required',
|
||||||
|
(v: string) => (v && v.length >= 6 && v.length <= 16) || '长度要求6~16'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
this.$api.auth.login(this.formInline.user, this.formInline.password).Start(
|
||||||
|
data => {
|
||||||
|
if (util.checkLogin()) {
|
||||||
|
// this.$message.success('登录成功')
|
||||||
|
// EventBus.$emit('login', true)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$router.push({name: 'home'})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// this.$message.error('用户名或密码错误')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// this.$message.error('网络错误!')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
created() {
|
||||||
|
console.log(this.formInline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
118
oaf/src/views/register.vue
Normal file
118
oaf/src/views/register.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<v-row class="fill-height" align="center" justify="center" style="background: #ebebeb">
|
||||||
|
<v-col cols="12" sm="8" md="6" lg="4" xl="3">
|
||||||
|
<v-card class="elevation-12 mx-5" style="opacity: 0.8">
|
||||||
|
<v-row justify="center">
|
||||||
|
<v-card class="elevation-1 mt-n7 primary" style="width: 80%">
|
||||||
|
<v-card-actions>
|
||||||
|
<v-row>
|
||||||
|
<v-icon
|
||||||
|
style="position: absolute;left: 10px;top:19px;z-index: 1"
|
||||||
|
@click="$router.back()"
|
||||||
|
size="36"
|
||||||
|
>mdi-arrow-left-circle
|
||||||
|
</v-icon>
|
||||||
|
<v-col cols="12" class="text-center">
|
||||||
|
<h1 class="display-2 ">注册</h1>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-row>
|
||||||
|
<v-card-text class="text-center">
|
||||||
|
<v-form ref="form">
|
||||||
|
<v-text-field
|
||||||
|
type="text"
|
||||||
|
prepend-inner-icon="mdi-account-circle"
|
||||||
|
v-model="form.username"
|
||||||
|
label="账号"
|
||||||
|
:rules="ruleInline.user"
|
||||||
|
:counter="16"
|
||||||
|
>
|
||||||
|
</v-text-field>
|
||||||
|
<v-text-field
|
||||||
|
type="password"
|
||||||
|
v-model="form.passwd"
|
||||||
|
label="密码"
|
||||||
|
prepend-inner-icon="mdi-lock"
|
||||||
|
:rules="ruleInline.password"
|
||||||
|
:counter="16"
|
||||||
|
></v-text-field>
|
||||||
|
<v-text-field
|
||||||
|
type="password"
|
||||||
|
v-model="form.passwdCheck"
|
||||||
|
label="密码"
|
||||||
|
prepend-inner-icon="mdi-lock"
|
||||||
|
:rules="ruleInline.passwordCheck"
|
||||||
|
:counter="16"
|
||||||
|
@keyup.enter="handleSubmit"
|
||||||
|
></v-text-field>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn type="primary" @click="handleSubmit">提交</v-btn>
|
||||||
|
<v-btn @click="handleReset()">重置</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang='ts'>
|
||||||
|
import {Component, Vue} from 'vue-property-decorator'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {}
|
||||||
|
})
|
||||||
|
export default class Register extends Vue {
|
||||||
|
form = {
|
||||||
|
passwd: '',
|
||||||
|
passwdCheck: '',
|
||||||
|
email: '',
|
||||||
|
username: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleInline = {
|
||||||
|
user: [
|
||||||
|
(v: string) => !!v || 'required',
|
||||||
|
(v: string) => (v && v.length >= 3 && v.length <= 16) || '长度要求3~16'
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
(v: string) => !!v || 'required',
|
||||||
|
(v: string) => (v && v.length >= 6 && v.length <= 16) || '长度要求6~16'
|
||||||
|
],
|
||||||
|
passwordCheck: [
|
||||||
|
(v: string) => !!v || 'required',
|
||||||
|
(v: string) => (v && v === this.form.passwd) || '密码不一致'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
if (!this.$refs.form.validate()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$api.user.register(this.form.username, this.form.passwd).Start(
|
||||||
|
(data) => {
|
||||||
|
// this.$message.success('注册成功!')
|
||||||
|
this.$router.push({name: 'login'})
|
||||||
|
},
|
||||||
|
(data) => {
|
||||||
|
if (data && data.code === '31011') {
|
||||||
|
// this.$message.error('用户名重复')
|
||||||
|
} else {
|
||||||
|
// this.$message.error('注册失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReset() {
|
||||||
|
this.form.username = ''
|
||||||
|
this.form.passwd = ''
|
||||||
|
this.form.passwdCheck = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -52,7 +52,7 @@ export default class Wx extends Vue {
|
|||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.uuid) {
|
if (this.uuid) {
|
||||||
this.api.app.get(this.uuid).Start(e => {
|
this.$api.app.get(this.uuid as string).Start(e => {
|
||||||
this.url = e.wx.url + '/api/wx/login/' + this.uuid
|
this.url = e.wx.url + '/api/wx/login/' + this.uuid
|
||||||
this.aid = e.wx.corp_id
|
this.aid = e.wx.corp_id
|
||||||
this.agentID = e.wx.agent_id
|
this.agentID = e.wx.agent_id
|
||||||
|
|||||||
@ -10,7 +10,7 @@ module.exports = {
|
|||||||
outputDir: '../sub/static',
|
outputDir: '../sub/static',
|
||||||
devServer: {
|
devServer: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 19528,
|
port: 19520,
|
||||||
disableHostCheck: true,
|
disableHostCheck: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'^/api': {
|
'^/api': {
|
||||||
|
|||||||
@ -76,7 +76,6 @@ func runSyncDB(*cli.Context) error {
|
|||||||
log.HandlerErrs(
|
log.HandlerErrs(
|
||||||
db.SetupJoinTable(&models.User{}, "Roles", &models.UserRole{}),
|
db.SetupJoinTable(&models.User{}, "Roles", &models.UserRole{}),
|
||||||
db.SetupJoinTable(&models.Role{}, "Users", &models.UserRole{}),
|
db.SetupJoinTable(&models.Role{}, "Users", &models.UserRole{}),
|
||||||
db.SetupJoinTable(&models.Role{}, "Auths", &models.RoleAuth{}),
|
|
||||||
db.AutoMigrate(&models.User{}, &models.Role{}, &models.Auth{}),
|
db.AutoMigrate(&models.User{}, &models.Role{}, &models.Auth{}),
|
||||||
)
|
)
|
||||||
log.HandlerErrs(
|
log.HandlerErrs(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user