Skip to content

Commit 21e3425

Browse files
authored
feat/role based access (#50)
* feat: add roles based access * feat: update roles env + todo * feat: add roles to update profile * feat: add role based oauth * feat: validate role for a given token
1 parent 1952705 commit 21e3425

28 files changed

+545
-142
lines changed

.env.sample

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ DATABASE_TYPE=sqlite
44
ADMIN_SECRET=admin
55
DISABLE_EMAIL_VERIFICATION=true
66
JWT_SECRET=random_string
7-
JWT_TYPE=HS256
7+
JWT_TYPE=HS256
8+
ROLES=user,admin
9+
DEFAULT_ROLE=user
10+
JWT_ROLE_CLAIM=role

TODO.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Task List
2+
3+
# Feature roles
4+
5+
For the first version we will only support setting roles master list via env
6+
7+
- [x] Support following ENV
8+
- [x] `ROLES` -> comma separated list of role names
9+
- [x] `DEFAULT_ROLE` -> default role to assign to users
10+
- [x] Add roles input for signup
11+
- [x] Add roles to update profile mutation
12+
- [x] Add roles input for login
13+
- [x] Return roles to user
14+
- [x] Return roles in users list for super admin
15+
- [x] Add roles to the JWT token generation
16+
- [x] Validate token should also validate the role, if roles to validate again is present in request

server/constants/constants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ var (
2323
DISABLE_EMAIL_VERIFICATION = "false"
2424
DISABLE_BASIC_AUTHENTICATION = "false"
2525

26+
// ROLES
27+
ROLES = []string{}
28+
DEFAULT_ROLE = ""
29+
JWT_ROLE_CLAIM = "role"
30+
2631
// OAuth login
2732
GOOGLE_CLIENT_ID = ""
2833
GOOGLE_CLIENT_SECRET = ""

server/db/db.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Manager interface {
2424
GetVerificationRequests() ([]VerificationRequest, error)
2525
GetVerificationByEmail(email string) (VerificationRequest, error)
2626
DeleteUser(email string) error
27+
SaveRoles(roles []Role) error
2728
}
2829

2930
type manager struct {
@@ -53,7 +54,7 @@ func InitDB() {
5354
if err != nil {
5455
log.Fatal("Failed to init db:", err)
5556
} else {
56-
db.AutoMigrate(&User{}, &VerificationRequest{})
57+
db.AutoMigrate(&User{}, &VerificationRequest{}, &Role{})
5758
}
5859

5960
Mgr = &manager{db: db}

server/db/roles.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package db
2+
3+
import "log"
4+
5+
type Role struct {
6+
ID uint `gorm:"primaryKey"`
7+
Role string
8+
}
9+
10+
// SaveRoles function to save roles
11+
func (mgr *manager) SaveRoles(roles []Role) error {
12+
res := mgr.db.Create(&roles)
13+
if res.Error != nil {
14+
log.Println(`Error saving roles`)
15+
return res.Error
16+
}
17+
18+
return nil
19+
}

server/db/user.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type User struct {
1717
CreatedAt int64 `gorm:"autoCreateTime"`
1818
UpdatedAt int64 `gorm:"autoUpdateTime"`
1919
Image string
20+
Roles string
2021
}
2122

2223
// SaveUser function to add user even with email conflict

server/env.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ func InitEnv() {
7373
constants.RESET_PASSWORD_URL = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/")
7474
constants.DISABLE_BASIC_AUTHENTICATION = os.Getenv("DISABLE_BASIC_AUTHENTICATION")
7575
constants.DISABLE_EMAIL_VERIFICATION = os.Getenv("DISABLE_EMAIL_VERIFICATION")
76+
constants.DEFAULT_ROLE = os.Getenv("DEFAULT_ROLE")
77+
constants.JWT_ROLE_CLAIM = os.Getenv("JWT_ROLE_CLAIM")
7678

7779
if constants.ADMIN_SECRET == "" {
7880
panic("root admin secret is required")
@@ -143,4 +145,33 @@ func InitEnv() {
143145
constants.DISABLE_EMAIL_VERIFICATION = "false"
144146
}
145147
}
148+
149+
rolesSplit := strings.Split(os.Getenv("ROLES"), ",")
150+
roles := []string{}
151+
defaultRole := ""
152+
153+
for _, val := range rolesSplit {
154+
trimVal := strings.TrimSpace(val)
155+
if trimVal != "" {
156+
roles = append(roles, trimVal)
157+
}
158+
159+
if trimVal == constants.DEFAULT_ROLE {
160+
defaultRole = trimVal
161+
}
162+
}
163+
if len(roles) > 0 && defaultRole == "" {
164+
panic(`Invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`)
165+
}
166+
167+
if len(roles) == 0 {
168+
roles = []string{"user", "admin"}
169+
constants.DEFAULT_ROLE = "user"
170+
}
171+
172+
constants.ROLES = roles
173+
174+
if constants.JWT_ROLE_CLAIM == "" {
175+
constants.JWT_ROLE_CLAIM = "role"
176+
}
146177
}

0 commit comments

Comments
 (0)