wip: 结构感觉还是要调整
This commit is contained in:
		| @@ -1,10 +1,15 @@ | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // platform:module:class:action | ||||
| // pro:*:*:* | ||||
| // pro:content:*:* | ||||
| // pro:content:secret_news:* | ||||
| // pro:content:secret_news:upload | ||||
| // admin:*:*:* | ||||
| // admin:audit:*:* | ||||
| // admin:audit:flow:* | ||||
| // admin:audit:flow:operate | ||||
|  | ||||
| type Privilege struct { | ||||
| 	CreatedAt int64  `json:"created_at" gorm:"column:created_at;autoCreateTime:milli"` | ||||
| @@ -17,5 +22,26 @@ type Privilege struct { | ||||
| } | ||||
|  | ||||
| func (p *Privilege) Validate() error { | ||||
| 	ss := strings.Split(p.Code, ":") | ||||
|  | ||||
| 	if len(ss) != 4 { | ||||
| 		return fmt.Errorf("privilege must consist of four parts: (platform:module:class:action)") | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range ss { | ||||
| 		if len(s) == 0 { | ||||
| 			return fmt.Errorf("privilege code parts must not be empty") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	code := strings.Clone(p.Code) | ||||
| 	for strings.HasSuffix(code, ":*") { | ||||
| 		code = code[:len(code)-2] | ||||
| 	} | ||||
|  | ||||
| 	if code != "*" && strings.Contains(code, "*") { | ||||
| 		return fmt.Errorf("privilege can only have trailing wildcard search") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										74
									
								
								model/privilege_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								model/privilege_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"uauth/internal/tool" | ||||
| ) | ||||
|  | ||||
| func TestPrivilege_Validate(t *testing.T) { | ||||
| 	type fields struct { | ||||
| 		Code string | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		fields  fields | ||||
| 		wantErr bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:    "全匹配", | ||||
| 			fields:  fields{Code: "*:*:*:*"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:    "部分全匹配1", | ||||
| 			fields:  fields{Code: "user:ok:*:*"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:    "部分全匹配2", | ||||
| 			fields:  fields{Code: "user:ok:nice:*"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:    "中间全匹配1", | ||||
| 			fields:  fields{Code: "user:*:*:ok"}, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:    "中间全匹配2", | ||||
| 			fields:  fields{Code: "user:*:nice:*"}, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:    "精确权限", | ||||
| 			fields:  fields{Code: "user:1:2:3"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			p := &Privilege{ | ||||
| 				Code: tt.fields.Code, | ||||
| 			} | ||||
| 			if err := p.Validate(); (err != nil) != tt.wantErr { | ||||
| 				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkPrivilegeValidate(b *testing.B) { | ||||
| 	ps := make([]*Privilege, 100000) | ||||
|  | ||||
| 	for i := 0; i < 100000; i++ { | ||||
| 		ps[i] = &Privilege{ | ||||
| 			Code: tool.RandomString(4) + ":" + tool.RandomString(5) + ":" + tool.RandomString(6) + ":" + tool.RandomString(7), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.ResetTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		_ = ps[i%100000].Validate() | ||||
| 	} | ||||
| } | ||||
| @@ -9,7 +9,12 @@ import ( | ||||
| 	"uauth/internal/sqlType" | ||||
| ) | ||||
|  | ||||
| type Status int64 | ||||
| type Status string | ||||
|  | ||||
| const ( | ||||
| 	StatusActive   Status = "active" | ||||
| 	StatusDisabled Status = "disabled" | ||||
| ) | ||||
|  | ||||
| type User struct { | ||||
| 	Id        uint64 `json:"id" gorm:"primaryKey;column:id"` | ||||
| @@ -20,7 +25,7 @@ type User struct { | ||||
| 	Username string `json:"username" gorm:"column:username;type:varchar(64);unique"` | ||||
| 	Password string `json:"-" gorm:"column:password;type:varchar(256)"` | ||||
|  | ||||
| 	Status Status `json:"status" gorm:"column:status;default:0"` | ||||
| 	Status Status `json:"status" gorm:"column:status;default:''"` | ||||
|  | ||||
| 	Nickname string `json:"nickname" gorm:"column:nickname;type:varchar(64)"` | ||||
| 	Avatar   string `json:"avatar" gorm:"column:avatar;type:varchar(256)"` | ||||
|   | ||||
							
								
								
									
										11
									
								
								rbac/rbac.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								rbac/rbac.go
									
									
									
									
									
								
							| @@ -24,6 +24,7 @@ func New(opts ...Option) (*Urbac, error) { | ||||
| 		rootPrivilege *model.Privilege | ||||
| 		rootRole      *model.Role | ||||
| 		rootScope     *model.Scope | ||||
| 		rootUser      *model.User | ||||
| 	) | ||||
|  | ||||
| 	for _, opt := range opts { | ||||
| @@ -60,5 +61,15 @@ func New(opts ...Option) (*Urbac, error) { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	rootUser = &model.User{ | ||||
| 		Username:  "admin", | ||||
| 		Password:  tool.NewPassword("123456"), | ||||
| 		Status:    model.StatusActive, | ||||
| 		Nickname:  "管理员", | ||||
| 		RoleNames: []string{"admin"}, | ||||
| 	} | ||||
|  | ||||
| 	u.newUser() | ||||
|  | ||||
| 	return u, nil | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user