Where to place business logic in Spring Hibernate app? - spring

I have an application written using the Spring and Hibernate frameworks. Everything works correctly but I do have one question: if controllers invoke business logic by calling service layer methods, where should certain code go, e.g. in the following code, should the code for setting up a new Person's Role and password be in the controller method processing the AddPerson page's POST request, or in a service layer method?
// Saves addPerson.jsp.
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String postAdd(#ModelAttribute("person") Person person) {
logger.debug("PersonController.postAdd called");
// Create random number for new Person's password.
person.setPassword(String.valueOf(Java_Utils.getRandomNumber()));
// Create role for new Person.
person.setRole("PERSON");
// Add Person.
personService.add(person);
// Set records.jsp
return "redirect:/demo/main/record/list";
}
This is of course only a simple example but I'm curious. The role of PERSON is to satisfy a constraint using Tomcat to prevent user's reaching an authenticated page.

It should be in the service layer. The Controller layer is for handling and translating GUI stuff. But the creation of an user and configure it correct is not GUI stuff it is a business (or technical) use case, therefore one should place it in a service.
`personService.createPersonWithRandomPassword();`

Related

Relax Security for a Spring Data REST Projection

I have a User class and I want to authorize access such that only a user gets to see what he is entitled to.
This was easily achievable using Spring Security in conjunction with Spring Data Rest where in JPA Repository I did below -
public interface UserRepository extends JPARepository<User,Integer> {
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
User findOne(#Param("id") Integer id);
}
In this way, a user when visits to Spring Data REST scaffolded URLs like -
/users/{id}
/users/{id}/userPosts
Only those logged in with {id} get to see these and everyone else gets 401 like I would have wanted.
My problem is that I have one of Projections which is a public view of each user and I am crating it using Spring Data Rest projections as below which I want to be accessible for every {id}
#Projection(name = "details", types = User.class)
public interface UserDetailsProjection {
..
}
So, /users/{id1}?projection=details as well as /users/{id2}?projection=details should give 200 OK and show data even though user is logged in by {id1}
I began implementing this by marking projection with #PreAuthorize("permitAll") but that won't work since Repository has harder security check. Can we have this functionality where for a projection we can relax security ?
I am using latest Spring Data Rest and Spring Security distributions
Seems reasonable to add a custom controller for this use-case.
Please also consider:
Evaluate access in projections using #Value annotations
Add another entity for the same database data but with different field set for read-only operations, e.g. using inheritance (be careful with caching, etc.) - depends on your data storage type
Modify model to split User entity into two different entities (profile, account) since they seem to have different access and possibly even operations
You can also add a ResourceProcessor<UserSummaryProjection> to evaluate access programmatically and replace resource content (projection) with a DTO
Example of evaluating access in projections with #Value annotations:
#Projection(types = User.class, name = "summary")
public interface UserSummaryProjection {
#Value("#{#userSecurity.canReadEmail(target) ? target.email: null}")
String getEmail();
}
Added spring security code in the data access layer is not a good idea. I would suggest you to add the #PreAuthorize annotation to the controller/service method. Since you have a query parameter, ?projection=details, you can have separate controller/service method for the details projection.
Add following to your details projection method:
#RequestMapping("/url", params = {"projection"})
#PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")

Spring: new() operator and autowired together

If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.

How to handle authorization with Breeze JS?

Currently my app looks at router parameter and logged in user (Principal.Identity) to authorize access to certain resources (e.g: Add student to your class [identity + class id]). However, If I'm not wrong, breeze js support just one bulk save. It seems to be that I will have to open each and every data and run through the validation/authorization. That is fine,
but what I may lose is nice separation of cross cutting concern out side my business logic (as a message handler) (finding what roles user has on the class) and nice Authroize annotation feature (just say what roles are needed). So do I have to trade off or is there better programming model which Breeze JS might suggest?
Update:
My question is more on how to separate the authorization (find assigned roles in message handler + verify if required roles are present by adding authorize attribute to controller methods) logic from business or data access logic. Without breeze, I will inspect the incoming message and its route parameter to fetch all its roles then in my put/post/delete methods I would annotate with required roles. I cannot use this technique with breeze (its not breeze's limitation, its trade off when you go for bulk save). So wanted to know if there is any programming model or design pattern already used by breeze guys. There is something on breeze's samples which is overriding context and using repository pattern, will follow that for now.
Breeze can have as many 'save' endpoints as you want. For example, a hypothetical server implementation might be
[BreezeController]
public class MyController : ApiController {
[HttpPost]
[Authorize(...)]
public SaveResult SaveCustomersAndOrders(JObject saveBundle) {
// CheckCustomersAndOrders would be a custom method that validates your data
ContextProvider.BeforeSaveEntitiesDelegate = CheckCustomerAndOrders;
return ContextProvider.SaveChanges(saveBundle);
}
[HttpPost]
[Authorize]
public SaveResult SaveSuppliersAndProducts(JObject saveBundle) {
...
}
You would call these endpoints like this
var so = new SaveOptions({ resourceName: "SaveWithFreight2", tag: "freight update" });
myEntityManager.saveChanges(customerAndOrderEntities, {
resourceName: "SaveCustomersAndOrder" }
).then(...)
or
myEntityManager.saveChanges(supplierAndProductEntities, {
resourceName: "SaveSuppliersAndProducts" }
).then(...)
Authorization is mediated via the [Authorize] attribute on each of the [HttpPost] methods. You can read more about the [Authorize] attribute here:
http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/
The proper way to do this IMHO is to separate the endpoint authorization and the database actions authorization.
First, create an entity that manages the grands per controller/method and role. For each method you have a value allowed - not allowed for the specific role. You create a special attribute (subclass of Authorize) that you apply to your controllers (breeze or plain web api) that reads the data and decides whether the specific endpoint can be called for the user/role. Otherwise it throws the Unauthorized exception.
On the breeze side (client) you extend the default adapter settings with a method that adds the authentication headers from identity that you received at login, something like this :
var origAjaxCtor = breeze.config.getAdapterInstance('ajax');
$.extend(true, origAjaxCtor.defaultSettings, Security.getAuthenticationHeaders());
On the server, add a second entity that manages the authorization for the CRUD operations. You need a table like (EntityName, AllowInsert, AllowUpdate, AllowDelete). Add a BeforeSave event on the Context Manager or on the ORM (EF or something else) that loops all entities and applies the policy specified on the table above.
This way you have a clear separation of the endpoint logic from the backend CRUD logic.
In all cases the authorization logic should first be implemented server side and if needed should be pushed to the clients.
The way breeze is implemented and with the above design you should not need more than 1 save endpoint.
Hope it helps.
However, If I'm not wrong, breeze js support just one bulk save.
That is entirely wrong. You have free reign to create your own save methods. Read the docs, it's all there.

Exposing entities through services and partial responses

What do you think about exposing domain entities through services? I tried it in an application, but I came to the conclusion that exposing domain model to the client is not such a good idea.
Advantages:
Really easy to transport data from-to client
List item
(De)Serialization is really easy: just put jackson in the classpath and it will handle it. No extra logic is needed.
No need to duplicate entities POJOs. At least in early stages, the API resources will be pretty much the same as the domain model.
Disadvantages:
The API's get very tightly coupled to the model and you can't change the model without affecting the API
Partial responses. There are cases where you don't want to return all the fields of the entities, just some of them. How do you accomplish it?
So, let's take the following REST example. The following API declares that GET on the user resource returns the following information.
GET
/users/12
{
"firstName":"John",
"lastName":"Poe"
"address":"my street"
}
Usually, I would create a User entity, a user service to return the user and a REST controller to serve the request like this:
#RequestMapping("/users/{id}")
public #ResponseBody User getUser(#PathVariable Long id) {
return userService.findById(id);
}
Should I avoid returning the User entity?
If yes, should I create another class and handle myself the mapping between this class and the entity?
Is there a pattern for this?
How to accomplish partial expansion? (i.e. return only the firstName and lastName for the user)
P.S: using #JSONFilter and ObjectMapper to accomplish partial responses seems too heavyweight to me because you loose the beauty of spring data

MVC design pattern model logic

According to the MVC design pattern, if we create a user (database work) and we have to send a mail with an activation code to the user, would this fit in the model or in the controller, after the model created the database record?
The MVC pattern is used to create an abstraction between the business logic (the model) and the GUI (the view). The controller is just an adapter (google adapter pattern) between those two blocks.
Hence the controller should only have code which is used to fetch the required information from the controller and adopt it so it fits the view. Any other logic should be in the model.
That only make sense if you understand that the model is not a single class but all of your business logic.
Example (implementation specific, but I hope that you understand):
public class UserController : Controller
{
// notice that it's a view model and not a model
public ActionResult Register(RegisterViewModel model)
{
UserService service;
User user = service.Register(model.UserName);
return View("Created");
}
}
// this class is located in the "model"
public class UserService
{
public User Register(string userName)
{
// another class in the "model"
var repository = new UserRepository();
var user = repository.Create(userName);
// just another "model" class
var emailService = new EmailService();
emailService.SendActivationEmail(user.Email);
return user;
}
}
MVC and MVC-inspired design patterns are combination of two layers:
Presentation layer
Model layer
Presentation layer is made up from views, controllers and (mostly in web-oriented solutions) templates. This layer deals with user interaction. It recognizes user input, produces responses and governs other aspect of user interface. The controllers, based on user interaction, change the state of model layer.
The model layer deals with domain business rules and interacts with different forms of storage. Model layer, just like presentation layer, is no any single object or class, but a group of structures with different responsibilities.
In this case, it would make sense for the service, which deals with user management, to use the different structures, that would both send the verification email, create an account and store this newly created user.
Services in model layer act like the barrier, that isolated the presentation layer from business logic. They deal with interaction between domain objects and storage abstractions (data mappers, repositories, units of work, etc.).
TL;DR
Email, with activation code for the newly created user, should be sent from model layer.
The controller is an object which simplifies and delegates messages to the model objects.
What you will have is an Interface object (or boundary object) within your model that represents the link between two systems (your system and email). class EmailClient. Your model objects will collaborate with this object when required.

Resources