feat: allow regular users to login to the UI
This commit is contained in:
parent
e0308acef3
commit
6978790e96
|
@ -31,6 +31,14 @@ func userId(ctx context.Context) string {
|
|||
return usr.ID
|
||||
}
|
||||
|
||||
func loggedUser(ctx context.Context) *model.User {
|
||||
user := ctx.Value("user")
|
||||
if user == nil {
|
||||
return &model.User{}
|
||||
}
|
||||
return user.(*model.User)
|
||||
}
|
||||
|
||||
func (r sqlRepository) newSelect(options ...model.QueryOptions) SelectBuilder {
|
||||
sq := Select().From(r.tableName)
|
||||
sq = r.applyOptions(sq, options...)
|
||||
|
|
|
@ -85,10 +85,18 @@ func (r *userRepository) UpdateLastAccessAt(id string) error {
|
|||
}
|
||||
|
||||
func (r *userRepository) Count(options ...rest.QueryOptions) (int64, error) {
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin {
|
||||
return 0, rest.ErrPermissionDenied
|
||||
}
|
||||
return r.CountAll(r.parseRestOptions(options...))
|
||||
}
|
||||
|
||||
func (r *userRepository) Read(id string) (interface{}, error) {
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin && usr.ID != id {
|
||||
return nil, rest.ErrPermissionDenied
|
||||
}
|
||||
usr, err := r.Get(id)
|
||||
if err == model.ErrNotFound {
|
||||
return nil, rest.ErrNotFound
|
||||
|
@ -97,6 +105,10 @@ func (r *userRepository) Read(id string) (interface{}, error) {
|
|||
}
|
||||
|
||||
func (r *userRepository) ReadAll(options ...rest.QueryOptions) (interface{}, error) {
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin {
|
||||
return nil, rest.ErrPermissionDenied
|
||||
}
|
||||
return r.GetAll(r.parseRestOptions(options...))
|
||||
}
|
||||
|
||||
|
@ -109,17 +121,25 @@ func (r *userRepository) NewInstance() interface{} {
|
|||
}
|
||||
|
||||
func (r *userRepository) Save(entity interface{}) (string, error) {
|
||||
usr := entity.(*model.User)
|
||||
err := r.Put(usr)
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin {
|
||||
return "", rest.ErrPermissionDenied
|
||||
}
|
||||
u := entity.(*model.User)
|
||||
err := r.Put(u)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return usr.ID, err
|
||||
return u.ID, err
|
||||
}
|
||||
|
||||
func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
||||
usr := entity.(*model.User)
|
||||
err := r.Put(usr)
|
||||
u := entity.(*model.User)
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin && usr.ID != u.ID {
|
||||
return rest.ErrPermissionDenied
|
||||
}
|
||||
err := r.Put(u)
|
||||
if err == model.ErrNotFound {
|
||||
return rest.ErrNotFound
|
||||
}
|
||||
|
@ -127,7 +147,11 @@ func (r *userRepository) Update(entity interface{}, cols ...string) error {
|
|||
}
|
||||
|
||||
func (r *userRepository) Delete(id string) error {
|
||||
err := r.Delete(id)
|
||||
usr := loggedUser(r.ctx)
|
||||
if !usr.IsAdmin && usr.ID != id {
|
||||
return rest.ErrPermissionDenied
|
||||
}
|
||||
err := r.delete(Eq{"id": id})
|
||||
if err == model.ErrNotFound {
|
||||
return rest.ErrNotFound
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ func handleLogin(ds model.DataStore, username string, password string, w http.Re
|
|||
"token": tokenString,
|
||||
"name": user.Name,
|
||||
"username": username,
|
||||
"isAdmin": user.IsAdmin,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -148,10 +149,6 @@ func validateLogin(userRepo model.UserRepository, userName, password string) (*m
|
|||
if u.Password != password {
|
||||
return nil, nil
|
||||
}
|
||||
if !u.IsAdmin {
|
||||
log.Warn("Non-admin user tried to login", "user", userName)
|
||||
return nil, nil
|
||||
}
|
||||
err = userRepo.UpdateLastLoginAt(u.ID)
|
||||
if err != nil {
|
||||
log.Error("Could not update LastLoginAt", "user", userName)
|
||||
|
@ -164,6 +161,7 @@ func createToken(u *model.User) (string, error) {
|
|||
claims := token.Claims.(jwt.MapClaims)
|
||||
claims["iss"] = consts.JWTIssuer
|
||||
claims["sub"] = u.UserName
|
||||
claims["adm"] = u.IsAdmin
|
||||
|
||||
return touchToken(token)
|
||||
}
|
||||
|
@ -176,11 +174,10 @@ func touchToken(token *jwt.Token) (string, error) {
|
|||
return token.SignedString(jwtSecret)
|
||||
}
|
||||
|
||||
func userFrom(claims jwt.MapClaims) *model.User {
|
||||
user := &model.User{
|
||||
UserName: claims["sub"].(string),
|
||||
}
|
||||
return user
|
||||
func contextWithUser(ctx context.Context, ds model.DataStore, claims jwt.MapClaims) context.Context {
|
||||
userName := claims["sub"].(string)
|
||||
user, _ := ds.User(ctx).FindByUsername(userName)
|
||||
return context.WithValue(ctx, "user", user)
|
||||
}
|
||||
|
||||
func getToken(ds model.DataStore, ctx context.Context) (*jwt.Token, error) {
|
||||
|
@ -217,7 +214,7 @@ func Authenticator(ds model.DataStore) func(next http.Handler) http.Handler {
|
|||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
|
||||
newCtx := context.WithValue(r.Context(), "loggedUser", userFrom(claims))
|
||||
newCtx := contextWithUser(r.Context(), ds, claims)
|
||||
newTokenString, err := touchToken(token)
|
||||
if err != nil {
|
||||
log.Error(r, "signing new token", err)
|
||||
|
|
|
@ -20,10 +20,12 @@ const App = () => (
|
|||
layout={Layout}
|
||||
loginPage={Login}
|
||||
>
|
||||
<Resource name="artist" {...artist} options={{ subMenu: 'library' }} />
|
||||
<Resource name="album" {...album} options={{ subMenu: 'library' }} />
|
||||
<Resource name="song" {...song} options={{ subMenu: 'library' }} />
|
||||
<Resource name="user" {...user} />
|
||||
{(permissions) => [
|
||||
<Resource name="artist" {...artist} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
|
||||
permissions === 'admin' ? <Resource name="user" {...user} /> : null
|
||||
]}
|
||||
</Admin>
|
||||
)
|
||||
export default App
|
||||
|
|
|
@ -25,6 +25,7 @@ const authProvider = {
|
|||
localStorage.setItem('token', response.token)
|
||||
localStorage.setItem('name', response.name)
|
||||
localStorage.setItem('username', response.username)
|
||||
localStorage.setItem('role', response.isAdmin ? 'admin' : 'regular')
|
||||
return response
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -59,13 +60,17 @@ const authProvider = {
|
|||
return Promise.resolve()
|
||||
},
|
||||
|
||||
getPermissions: (params) => Promise.resolve()
|
||||
getPermissions: () => {
|
||||
const role = localStorage.getItem('role')
|
||||
return role ? Promise.resolve(role) : Promise.reject()
|
||||
}
|
||||
}
|
||||
|
||||
const removeItems = () => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('name')
|
||||
localStorage.removeItem('username')
|
||||
localStorage.removeItem('role')
|
||||
}
|
||||
|
||||
export default authProvider
|
||||
|
|
Loading…
Reference in New Issue