Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Service layer design, where to check permissions, and how to handle UI layer

@RequestMapping(value = "/products/create", method = RequestMethod.POST)
public ModelAndView create(@Valid ProductForm productForm, BindingResult bindingResult,
                           HttpServletRequest request) {
    SessionContext sessionContext = (SessionContext) request.getAttribute("sessionContext");

    ModelAndView mav = new ModelAndView("products/new");
    mav.addObject("errors", bindingResult.getAllErrors());
    mav.addObject("productForm", productForm);

    int newProductId = -1;

    if (!bindingResult.hasErrors()) {

        List<Product> products = productService.find...(...);
        if (products != null...) {
            bindingResult.addError(new ObjectError("Products", "..."));
        }

        // only try and create if no errors so far
        if (!bindingResult.hasErrors()) {
            newProductId = productService.create(..., productForm);
            if (newProductId <= 0) {
                bindingResult.addError(new ObjectError("Products", "..."));
            }
        }
    }

    if (bindingResult.hasErrors()) {
        return mav;
    }


    return new ModelAndView("redirect:/products/show/" + newProductId);
}

So the above describes the UI side of things (using Spring MVC).

Now, how should I be designing the service layer, so in this example the ProductServiceImpl has a create method that will will create the product and persist it in the database.

I have to check for permissions, based on the users role etc.

I could to this in the UI layer by first checking if the user has permissions to create a product:

if(permissionService.hasPermission(.....)) {
  newProductId = productService.create(....)
}

But this ties this logic into the UI layer, I think it should be in the create method itself:

public class ProductServiceImpl implements ProductService {

  @Autowired
  PermissionService permissionService;

  ..

  @Override
  public int create(...., final ProductForm productForm) {

     boolean canCreateProduct = productService.hasPermissions(.....);

     if(canCreateProduct) {
       Product product = ..... (productForm);
       productDao.save(product);
       return product.getId();
     }   
  }
}

But the problem I can't understand is if I put the permission check in ProductServiceImpl.create method, how do I report back to the UI layer that you don't have permissions to do this?

If you say I should throw an exception, then my UI layer looks very cluttered as I will have so many exceptions to handle based on the various checks I need to perform.

What should I be doing here?

like image 613
Blankman Avatar asked Dec 06 '25 15:12

Blankman


1 Answers

Permission checks like this should/could be done with AOP, through means of a mechanism like CDI's interceptors. Spring has method interceptors serving the same purpose (see AOP in Spring). Throwing an exception in case of insufficient rights is the correct approach.

That said, I see your problem, but the common solution is quite simple: Your UI receives the rights of its user post-login (or retrieves them through some UserService). Using this info, you adjust the operations you expose in the UI. In your example, you do not display the operation for creating a new product if the user is not allowed to do so.

You will probably still want to handle the exception though (let's say in case a user's rights are modified server-side in the meantime) and display an error if it occurs.

like image 151
Torious Avatar answered Dec 09 '25 14:12

Torious



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!