Salut
Lucrand singur de aproape 2 ani, ma vad nevoit sa vin cu intrebari tampite pe forum, pentru a ma asigura ca nu o iau pe aratura povestea e destul de simpla:
Am un api cu un endpoint de delete dashboard, de tip DELETE in care trimit parametrul in url ( apiUrl/dashboards/delete?id=123
). Nimic complicat, din controller ajung in serviciu, unde mai intai sterg dependintele, si apoi dashboardul.
controller:
def delete(id: Int) = Action.async { request =>
service.delete(id)
}
service:
def delete(id: Int) = {
val deps = for {
f1 <- repo.deleteWidgets(id) // returneaza true
f2 <- repo.deleteUsers(id) // returneaza true
} yield (f1, f2)
deps map { results => {
results match {
case (true, true) => repo.delete(id)
case _ => throw new Exception("Dependintele nu pot fi sterse")
}
}
}
}
Pana aici sper ca fluxul este ok, altul nu stiu Problema apare dupa o noua dezvoltare. Un user (care este singurul admin al unui dashboard) poate sa sharuiasca altuia cu posibilitatea de editare/stergere widgeturi, dar fara a putea sterge dashboardul. Asa am ajuns la ideea ca trebuie sa trimit si userId-ul celui conectat, din frontend, si endpointul meu va avea parametrii ?id=123&userId=7, doar ca nu mi-a placut ideea de a trimite 2 parametrii pentru delete si nici nu cred ca am vazut pe undeva practica asta. Mi-am adus rapid aminte ca folosesc Bearer Token si ca pot salva userId’ul acolo si asa il pot scoate direct din request
in backend.
astfel controllerul devine:
def delete(id: Int) = Action.async { request =>
val claims = authService.decodeToken(request)
service.delete(id, claims.userId)
}
iar serviciul:
def delete(id: Int, userId: Int) = {
// am o tabela de legatura DashboardUser cu campurile dashboardId, userId, role
repo.getByIds(id, userId) map {
(du: DashboardUser) => du.role match {
case "admin" => // tot codul serviciului de mai sus
case _ => throw new Exception("Nu ai permisiunea de a sterge acest dashboard")
}
}
val deps = for {
f1 <- repo.deleteWidgets(id)
f2 <- repo.deleteUsers(id)
} yield (f1, f2)
deps map { results => {
results match {
case (true, true) => repo.delete(id)
case _ => throw new Exception("Can not delete dependencies")
}
}
}
}
Ca de obicei am lungit postarile prea mult incerc sa fac un rezumat:
- in controller, scot userId-ul celui care face actiunea, din token
- verific daca userul respectiv are rolul “admin” pentru a putea sterge entitatea
- sterg dependintele
- sterg entitatea
Stiu ca astea putea fi evitata din frontend, ascunzand butonul de “delete” userilor care nu au rolul de “admin”, dar imi place sa lucrez cu dubla validare si incerc sa nu las “portite” in backend
Si intrebarea … este o abordare corecta tot ce-am scris mai sus? Exista si alte variante? merci
Nu cred ca are relevanta, dar limbajul este Scala (Play framework)