feat:完善项目
This commit is contained in:
235
app/service/auth.go
Normal file
235
app/service/auth.go
Normal file
@ -0,0 +1,235 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
casbin "github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
gormadapter "github.com/casbin/gorm-adapter/v3"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type (
|
||||
Auth struct {
|
||||
enforcer *casbin.Enforcer
|
||||
}
|
||||
|
||||
// Permission 权限信息
|
||||
Permission struct {
|
||||
Identity *Identity // 身份信息
|
||||
Roles []string // 角色
|
||||
Request []*AuthRequest
|
||||
}
|
||||
|
||||
// Identity 身份信息
|
||||
Identity struct {
|
||||
Tenant string // 平台-小区
|
||||
User string // 用户唯一标识
|
||||
}
|
||||
|
||||
AuthRequest struct {
|
||||
Url string
|
||||
Method string
|
||||
}
|
||||
|
||||
IdentityPermission func(tenant, user string) *Permission
|
||||
)
|
||||
|
||||
var auth *Auth
|
||||
|
||||
// adapter 规则
|
||||
var adapter = map[string]func(params ...interface{}) interface{}{
|
||||
"mysql": adapterForOrm, "sqlite": adapterForOrm,
|
||||
}
|
||||
|
||||
// adapterForOrm
|
||||
func adapterForOrm(params ...interface{}) interface{} {
|
||||
db := params[0].(*gorm.DB)
|
||||
obj := params[1].(string)
|
||||
adapter, _ := gormadapter.NewAdapterByDBUseTableName(db, "", obj)
|
||||
return adapter
|
||||
}
|
||||
|
||||
// Register 注册权限
|
||||
// 多平台 admin tenant1, data1, read (角色-域-用户-事件)
|
||||
// p admin tenant1, data1, read (角色-域-用户-事件)
|
||||
// g alice, admin, tenant1 (用户-角色-域)
|
||||
func (this *Auth) Register() func(mode string, params ...interface{}) interface{} {
|
||||
return func(mode string, params ...interface{}) interface{} {
|
||||
m := model.NewModel()
|
||||
m.AddDef("r", "r", "sub, dom, obj, act")
|
||||
m.AddDef("p", "p", "sub, dom, obj, act")
|
||||
m.AddDef("g", "g", "_, _, _")
|
||||
m.AddDef("e", "e", "some(where (p.eft == allow))")
|
||||
m.AddDef("m", "m", "g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act")
|
||||
|
||||
a, has := adapter[mode]
|
||||
|
||||
if has {
|
||||
this.enforcer, _ = casbin.NewEnforcer(m, a(params...))
|
||||
this.enforcer.EnableAutoSave(true)
|
||||
} else {
|
||||
this.enforcer, _ = casbin.NewEnforcer(m)
|
||||
}
|
||||
auth = this
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// tenantIdentity 平台租户信息
|
||||
func (this *Identity) tenantIdentity() string {
|
||||
return fmt.Sprintf("%s%s", "t_", this.Tenant)
|
||||
}
|
||||
|
||||
// userIdentity 用户身份信息
|
||||
func (this *Identity) userIdentity() string {
|
||||
return fmt.Sprintf("%s%s", "u_", this.User)
|
||||
}
|
||||
|
||||
// roleIdentity 角色身份信息
|
||||
func (this *Permission) roleIdentity() []string {
|
||||
roles := make([]string, 0)
|
||||
|
||||
for _, v := range this.Roles {
|
||||
roles = append(roles, fmt.Sprintf("%s%s", "r_", v))
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
||||
// AddRoleForUser 增加用户角色
|
||||
func (this *Permission) AddRoleForUser() (bool, error) {
|
||||
if this.Roles == nil || len(this.Roles) <= 0 {
|
||||
return false, errors.New("无角色信息")
|
||||
}
|
||||
for _, role := range this.roleIdentity() {
|
||||
if _, err := auth.enforcer.AddRoleForUser(this.Identity.userIdentity(), role, this.Identity.tenantIdentity()); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// DeleteRoleForUser 删除用户角色
|
||||
//func (this *Permission) DeleteRoleForUser() (bool, error) {
|
||||
// if this.Roles == nil || len(this.Roles) <= 0 {
|
||||
// return false, errors.New("角色信息不存在")
|
||||
// }
|
||||
// for _, role := range this.roleIdentity() {
|
||||
// status, err := auth.enforcer.DeleteRoleForUser(this.Identity.userIdentity(), role, this.Identity.tenantIdentity())
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// } else if !status {
|
||||
// return false, errors.New("删除失败")
|
||||
// }
|
||||
// }
|
||||
// return true, nil
|
||||
//}
|
||||
|
||||
// DeleteRolesForUser 删除用户所有角色
|
||||
func (this *Permission) DeleteRolesForUser(allTenant bool) (bool, error) {
|
||||
if allTenant {
|
||||
return auth.enforcer.DeleteRolesForUser(this.Identity.userIdentity())
|
||||
}
|
||||
return auth.enforcer.DeleteRolesForUser(this.Identity.userIdentity(), this.Identity.tenantIdentity())
|
||||
}
|
||||
|
||||
//// AddPolicy 增加规则
|
||||
//func (this *Permission) AddPolicy() (bool, error) {
|
||||
// if this.Request == nil || len(this.Request) <= 0 {
|
||||
// return false, errors.New("请求事件错误")
|
||||
// }
|
||||
// return auth.enforcer.AddPolicy(this.roleIdentity()[0], this.Identity.tenantIdentity(), this.Request[0].Url, this.Request[0].Method)
|
||||
//}
|
||||
|
||||
// AddPolicies TODO:增加多个规则
|
||||
func (this *Permission) AddPolicies() (bool, error) {
|
||||
if this.Request == nil || len(this.Request) <= 0 {
|
||||
return false, errors.New("请求事件错误")
|
||||
}
|
||||
rules := make([][]string, 0)
|
||||
|
||||
for _, s := range this.Request {
|
||||
rules = append(rules, []string{
|
||||
this.roleIdentity()[0], this.Identity.tenantIdentity(), s.Url, s.Method,
|
||||
})
|
||||
}
|
||||
return auth.enforcer.AddPolicies(rules)
|
||||
}
|
||||
|
||||
//// RemovePolicy TODO:删除规则
|
||||
//func (this *Permission) RemovePolicy() (bool, error) {
|
||||
// if this.Request == nil || len(this.Request) <= 0 {
|
||||
// return false, errors.New("请求事件错误")
|
||||
// }
|
||||
// return auth.enforcer.RemovePolicy(this.roleIdentity()[0], this.Identity.tenantIdentity(), this.Request[0].Url, this.Request[0].Method)
|
||||
//}
|
||||
//
|
||||
//// RemovePolicies 删除多个规则
|
||||
//func (this *Permission) RemovePolicies() (bool, error) {
|
||||
// rules := make([][]string, 0)
|
||||
//
|
||||
// for _, s := range this.Request {
|
||||
// rules = append(rules, []string{
|
||||
// this.roleIdentity()[0], this.Identity.tenantIdentity(), s.Url, s.Method,
|
||||
// })
|
||||
// }
|
||||
// return auth.enforcer.RemovePolicies(rules)
|
||||
//}
|
||||
|
||||
// RemoveRolePolicy 删除角色的所有规则
|
||||
func (this *Permission) RemoveRolePolicy() (bool, error) {
|
||||
if this.Roles == nil || len(this.Roles) <= 0 {
|
||||
return false, errors.New("角色信息不存在")
|
||||
}
|
||||
return auth.enforcer.RemoveFilteredPolicy(0, this.roleIdentity()[0], this.Identity.tenantIdentity())
|
||||
}
|
||||
|
||||
// RemoveNamedGroupingPolicies 删除租户下角色的权限
|
||||
func (this *Permission) RemoveNamedGroupingPolicies() (bool, error) {
|
||||
rules := make([][]string, 0)
|
||||
|
||||
roles := this.roleIdentity()
|
||||
|
||||
for _, role := range roles {
|
||||
rule := make([]string, 0)
|
||||
for _, request := range this.Request {
|
||||
rule = append(rule, role, this.Identity.tenantIdentity(), request.Url, request.Method)
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
return auth.enforcer.RemoveNamedGroupingPolicies("g", rules)
|
||||
}
|
||||
|
||||
// RemoveFilteredGroupingPolicy 删除组权限规则
|
||||
func (this *Permission) RemoveFilteredGroupingPolicy() (bool, error) {
|
||||
return auth.enforcer.RemoveFilteredGroupingPolicy(0, this.Identity.tenantIdentity())
|
||||
}
|
||||
|
||||
// HasPolicy 检查访问权限
|
||||
func (this *Permission) Enforce() (bool, error) {
|
||||
if this.Request == nil || len(this.Request) <= 0 {
|
||||
return false, errors.New("请求事件错误")
|
||||
}
|
||||
return auth.enforcer.Enforce(this.Identity.userIdentity(), this.Identity.tenantIdentity(), this.Request[0].Url, "*")
|
||||
}
|
||||
|
||||
// NewAuth
|
||||
func NewAuth() *Auth {
|
||||
return &Auth{}
|
||||
}
|
||||
|
||||
// NewPermission
|
||||
func NewPermission(roles []string, act ...*AuthRequest) IdentityPermission {
|
||||
return func(tenant, user string) *Permission {
|
||||
return &Permission{
|
||||
Identity: &Identity{
|
||||
Tenant: tenant,
|
||||
User: user,
|
||||
},
|
||||
Roles: roles,
|
||||
Request: act,
|
||||
}
|
||||
}
|
||||
}
|
106
app/service/captcha.go
Normal file
106
app/service/captcha.go
Normal file
@ -0,0 +1,106 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
type Param struct {
|
||||
obj interface{}
|
||||
}
|
||||
|
||||
type CaptchaInfo struct {
|
||||
Key string `json:"key"`
|
||||
Captcha string `json:"captcha"`
|
||||
}
|
||||
|
||||
type CaptchaType string
|
||||
|
||||
const (
|
||||
CaptchaTypeForDefault CaptchaType = "default"
|
||||
CaptchaTypeForAudio CaptchaType = "audio"
|
||||
CaptchaTypeForString CaptchaType = "string"
|
||||
CaptchaTypeForMath CaptchaType = "math"
|
||||
CaptchaTypeForChinese CaptchaType = "chinese"
|
||||
)
|
||||
|
||||
var drivers = map[CaptchaType]func() base64Captcha.Driver{
|
||||
CaptchaTypeForDefault: captchaForDigit,
|
||||
CaptchaTypeForAudio: captchaForAudio,
|
||||
CaptchaTypeForString: captchaForString,
|
||||
CaptchaTypeForMath: captchaForMath,
|
||||
CaptchaTypeForChinese: captchaForChinese,
|
||||
}
|
||||
|
||||
var store = base64Captcha.DefaultMemStore
|
||||
|
||||
func captchaForDigit() base64Captcha.Driver {
|
||||
drive := new(base64Captcha.DriverDigit)
|
||||
drive.Width = 100
|
||||
drive.Height = 40
|
||||
drive.DotCount = 80
|
||||
drive.Length = 6
|
||||
drive.MaxSkew = 0.7
|
||||
return drive
|
||||
}
|
||||
|
||||
func captchaForAudio() base64Captcha.Driver {
|
||||
drive := new(base64Captcha.DriverAudio)
|
||||
drive.Language = "zh"
|
||||
drive.Length = 4
|
||||
return drive
|
||||
}
|
||||
|
||||
func captchaForString() base64Captcha.Driver {
|
||||
drive := new(base64Captcha.DriverString)
|
||||
drive.Width = 100
|
||||
drive.Width = 40
|
||||
drive.Source = "设想,你在,处理,消费者,的音,频输,出音,频可,能无,论什,么都,没有,任何,输出,或者,它可,能是,单声道,立体声,或是,环绕立,体声的,不想要,的值"
|
||||
drive.Length = 2
|
||||
return drive.ConvertFonts()
|
||||
}
|
||||
|
||||
func captchaForMath() base64Captcha.Driver {
|
||||
drive := new(base64Captcha.DriverMath)
|
||||
drive.Width = 100
|
||||
drive.Height = 40
|
||||
drive.NoiseCount = 1
|
||||
return drive.ConvertFonts()
|
||||
}
|
||||
|
||||
func captchaForChinese() base64Captcha.Driver {
|
||||
drive := new(base64Captcha.DriverChinese)
|
||||
drive.Width = 100
|
||||
drive.Width = 40
|
||||
drive.Source = "1234567890qwertyuioplkjhgfdsazxcvbnm"
|
||||
drive.Length = 4
|
||||
return drive.ConvertFonts()
|
||||
}
|
||||
|
||||
func (this *Param) Create() (*CaptchaInfo, error) {
|
||||
obj := this.obj.(CaptchaType)
|
||||
|
||||
drive, has := drivers[obj]
|
||||
|
||||
if !has {
|
||||
return nil, errors.New("参数异常")
|
||||
}
|
||||
c := base64Captcha.NewCaptcha(drive(), store)
|
||||
|
||||
key, captcha, err := c.Generate()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CaptchaInfo{Key: key, Captcha: captcha}, nil
|
||||
}
|
||||
|
||||
func (this *Param) Validate() bool {
|
||||
obj := this.obj.(*CaptchaInfo)
|
||||
return store.Verify(obj.Key, obj.Captcha, true)
|
||||
}
|
||||
|
||||
func Captcha(obj interface{}) *Param {
|
||||
return &Param{obj: obj}
|
||||
}
|
56
app/service/eventhub.go
Normal file
56
app/service/eventhub.go
Normal file
@ -0,0 +1,56 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// listener 监听
|
||||
type listener struct {
|
||||
handler ListenerHandle
|
||||
}
|
||||
|
||||
// listeners 监听器
|
||||
type listeners struct {
|
||||
listener map[interface{}]*listener
|
||||
mutex *sync.RWMutex
|
||||
}
|
||||
|
||||
// ListenerHandle 监听事件
|
||||
type ListenerHandle interface {
|
||||
Handle(args ...interface{})
|
||||
}
|
||||
|
||||
// listenerObject 监听器
|
||||
var listenerObject = &listeners{
|
||||
listener: make(map[interface{}]*listener, 0),
|
||||
mutex: new(sync.RWMutex),
|
||||
}
|
||||
|
||||
// Subscribe 注册事件
|
||||
func Subscribe(prefix interface{}, handler ListenerHandle) {
|
||||
listenerObject.mutex.Lock()
|
||||
defer listenerObject.mutex.Unlock()
|
||||
listenerObject.listener[prefix] = &listener{handler: handler}
|
||||
}
|
||||
|
||||
// Publish 推送事件
|
||||
func Publish(prefix interface{}, args ...interface{}) {
|
||||
listenerObject.mutex.RLock()
|
||||
defer listenerObject.mutex.RUnlock()
|
||||
listener, has := listenerObject.listener[prefix]
|
||||
if !has {
|
||||
return
|
||||
}
|
||||
listener.handler.Handle(args...)
|
||||
}
|
||||
|
||||
// Unsubscribe 取消监听
|
||||
func Unsubscribe(prefix interface{}) {
|
||||
listenerObject.mutex.Lock()
|
||||
defer listenerObject.mutex.Unlock()
|
||||
_, has := listenerObject.listener[prefix]
|
||||
if !has {
|
||||
return
|
||||
}
|
||||
delete(listenerObject.listener, prefix)
|
||||
}
|
28
app/service/session.go
Normal file
28
app/service/session.go
Normal file
@ -0,0 +1,28 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"SciencesServer/utils"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
UID uint64 `json:"uid"` // 唯一标识ID
|
||||
Token string `json:"token"` // token
|
||||
Name string `json:"name"` // 名称
|
||||
Mobile string `json:"mobile"` // 手机号码
|
||||
IsAdmin bool `json:"is_admin"` // 是否超管
|
||||
TenantID uint64 `json:"tenant_id"` // 租户ID
|
||||
TenantKey string `json:"tenant_key"` // 租户标识,用来区别分库管理
|
||||
}
|
||||
|
||||
func (this *Session) MarshalBinary() ([]byte, error) {
|
||||
return json.Marshal(this)
|
||||
}
|
||||
|
||||
func (this *Session) UnmarshalBinary(data []byte) error {
|
||||
return utils.FromJSONBytes(data, this)
|
||||
}
|
||||
|
||||
func NewSession() *Session {
|
||||
return &Session{}
|
||||
}
|
Reference in New Issue
Block a user