feat: allow regular users to login to the UI

This commit is contained in:
Deluan 2020-02-05 22:22:44 -05:00
parent e0308acef3
commit 6978790e96
5 changed files with 57 additions and 21 deletions

View File

@ -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...)

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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