保证spring mvc和hibernate的最佳实践

时间:2016-06-18 13:30:29

标签: angularjs hibernate rest spring-mvc spring-security

假设我有一个表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);
}

2 个答案:

答案 0 :(得分:0)

您需要考虑保护实体数据的编组和解组。

换句话说,对于非管理员用户,您只想将字段AB编组到客户端,并取消联合字段A和{{1}来自客户端。对于管理员用户,您希望对所有字段进行编组和解组。

当用户上下文不是管理员时,您需要防止向基于Javascript的客户端泄漏关于字段B的安全信息。根据字段C的值的安全性,阻止非管理员用户插入/更新字段C是不够的。

答案 1 :(得分:0)

不应该太困难:

  1. 使用相同或不同的控制器,为读/写创建单独的API,一组用于普通用户,另一组用于管理员用户。

  2. 使用spring security仅允许管理员访问Admin API。

  3. 对于处理普通用户读取的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;
            }
        }
    
  4. 对于写入,根据传入对象的内部ID从Hibernate中检索元素,并仅使用允许用户更新的传入对象中的那些字段进行更新,然后将该对象保留到数据库中。