假设我有一个表z 持有列a,b,c。
任何授权用户都可以使用a和b列,管理员只能使用c列。
我的hibernate实体基于表z。我的spring mvc控制器有一个读写方法。我可以使用spring security来保护mvc控制器使用角色。
问题是......我的客户端(通过rest / json与控制器进行角度交谈)可以通过设置c的值来访问所有列(即使客户端前端没有明确提供这一点),只需设置一个json对象即可并将其发送到控制器写入方法。同样调用read方法会将c列值返回给任何用户。
根据角色访问该表有什么好的做法?
好的,在一个简单的例子之下:
实体:
@Entity
@Table(name = "hotel")
@XmlRootElement
public class Hotel extends BaseEntity implements Serializable {
private String name;
private String street;
private String houseNo;
private String postalcode;
private String city;
private String country;
private String shortDesc;
private Boolean landing; // admin acceess only
}
后端立面:
@Component
public class HotelAccessImpl extends BackendBaseAccess implements HotelAccess {
@Autowired
private AccountAccess accountAccess;
@Override
public List<Hotel> findAll() {
TypedQuery<Hotel> query = getEm().createQuery("FROM Hotel WHERE DELETED = false ORDER BY CREATED DESC",
Hotel.class);
List<Hotel> results = query.getResultList();
return results;
}
@Override
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRES_NEW)
public Hotel upsert(Hotel hotel) {
if (find(hotel.getId()) == null) {
getEm().persist(hotel);
} else {
hotel = getEm().merge(hotel);
}
getEm().flush();
return hotel;
}
}
API(控制器,我限制访问&#34;仅限#34;在方法级别)
@RestController
@RequestMapping("hotel")
public class HotelController extends BaseController {
private static Logger logger = LogManager.getLogger(HotelController.class);
@Autowired
private FileAccess fileAccess;
@Autowired
private HotelAccess hotelAccess;
@Autowired
private MailAccess mailAccess;
@RequestMapping(value = "list", method = RequestMethod.GET)
public ResponseEntity<List<Hotel>> findAll() {
logger.info("FindAll");
return new ResponseEntity<List<Hotel>>(hotelAccess.findAll(), HttpStatus.OK);
}
@RequestMapping(value = "upsert", method = RequestMethod.POST)
public ResponseEntity<Hotel> upsert(@RequestBody Hotel hotel) {
logger.info("Upsert: " + hotel.getName());
if (isAuthorized(hotel.getAccount())) {
Hotel response = hotelAccess.upsert(hotel);
if (response.isInitial()) {
mailAccess.sendHotelUpsert(response);
}
return new ResponseEntity<Hotel>(response, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
@Secured({ "ROLE_ADMIN" })
@RequestMapping(value = "delete", method = RequestMethod.POST)
public ResponseEntity<Hotel> delete(@RequestBody Hotel hotel) {
logger.info("Delete: " + hotel.getId());
boolean deleted = hotelAccess.delete(hotel);
return (deleted) ? new ResponseEntity<>(HttpStatus.OK) : new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
答案 0 :(得分:0)
您需要考虑保护实体数据的编组和解组。
换句话说,对于非管理员用户,您只想将字段A
和B
编组到客户端,并取消联合字段A
和{{1}来自客户端。对于管理员用户,您希望对所有字段进行编组和解组。
当用户上下文不是管理员时,您需要防止向基于Javascript的客户端泄漏关于字段B
的安全信息。根据字段C
的值的安全性,阻止非管理员用户插入/更新字段C
是不够的。
答案 1 :(得分:0)
不应该太困难:
使用相同或不同的控制器,为读/写创建单独的API,一组用于普通用户,另一组用于管理员用户。
使用spring security仅允许管理员访问Admin API。
对于处理普通用户读取的API,在发送值之前,不要让普通用户看到Z的任何元素:
@RequestMapping(value = "/my/foo/{id}", method = RequestMethod.GET)
public Foo getFoo(@PathVariable String id, HttpServletResponse response) {
Foo foo = fooDao.getFoo(id);
if (foo != null) {
foo.setC(null);
return foo;
} else {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
}
}
对于写入,根据传入对象的内部ID从Hibernate中检索元素,并仅使用允许用户更新的传入对象中的那些字段进行更新,然后将该对象保留到数据库中。