用户加密机制设计初步完成

This commit is contained in:
veypi
2021-10-21 18:09:40 +08:00
parent cd7029c298
commit 82b64a4bb2
40 changed files with 1027 additions and 322 deletions
+27 -6
View File
@@ -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"`
+37 -14
View File
@@ -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"`
}
+23 -115
View File
@@ -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