sessions management in Spring MVC - spring

I am trying to do a simple android application that communicates with a Spring server.
I'd like to use Sessions to store data of each logged in User.
My App exchange Json objects with the server and the Request Mapping is like this:
#Controller
public class LoginController {
#Autowired
private IUserDao userDao;
#RequestMapping( value = "/loginJson",method = RequestMethod.POST)
public #ResponseBody loginResponse login(#RequestBody loginModel login) {
loginResponse response=userDao.checkCredentials(login.getUsername(),login.getPassword());
System.out.println("Result="+response.isSuccess());
System.out.println("Received:"+login.getUsername()+" "+login.getPassword());
return response;
}
}
The controller is working fine, but I can't figure out how to store a sessione variable. I found many documents explaining Spring Sessions, but each of them different from the other.
Someone can suggest me some simple way to do this or some kind of good tutorial?

Not sure what you mean by saying Spring session, but you can declare additional HttpSession parameter in your method, and then do whatever you like inside of the method. Is this what you wanted to find out?

Related

Implementing JSR-303 validation with crnk JSON API

I am fairly familiar with the JSR-303's #Valid annotation and have used it a couple of times in my #Controller classes. For example:
#PostMapping("/users")
ResponseEntity<String> addUser(#Valid #RequestBody User user) {
// persisting the user
return ResponseEntity.ok("User is valid");
}
Where User object is a typical class with annotations like #NotBlank or #NotNull on the fields.
However, I am trying to build a REST API based on JSON API using the crnk library and am trying to do the same validation, example:
#Override
public Subscription save(#Valid Subscription subscription) {
// code goes here
}
Unfortunately the validation doesn't work and I have tried both #Valid and #Validation.
Can anyone kindly show what is wrong with this code?
Thanks

Spring REST design public and authenticated API

I'm trying to design an application that should expose two global API path:
/ user must be authenticated
/public no authentication
Moreover /public API will offer light version of some / API by displaying less informations that is not authorize if no authentication is provided.
Even if Controller does not contains core function, some of them provide data validation or other check. Thus if I want to create a /public version of a current API I have 4 solutions:
Duplicate code
#Autowired / controller and use method call
forward request (I can't redirect because security filter will be applied)
Create Controller that manage both / and /public API
Is there any good practice or pattern for my scenario?
IMHO, Best way to solve this problem is by using 4th solution.
1st solution: First rule of computer science is you do not duplicate your code.
2nd solution: calling controller from another controller is a serious design flaw.
3rd solution: could have been a solution but ruled out by you.
4th solution: IMHO best one in your case
class MyController{
#RequestMapping("/getData")
public ResponseObject getData(#RequestBody SomeDTO dto){
Validator.validate(dto);
return myService.getData(dto);
}
#RequestMapping("/public/getData")
public ResponseObject getPublicData(#RequestBody SomeDTO dto){
Validator.validate(dto);
return myService.getPublicData(dto);
}
}
Filter data in your service layer.
It's possible to be achieved with Spring Security.
First, you will need to enable this URL to be called without security, like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
/** some security code **/
http
.authorizeRequests().antMatchers("/resources/**","/public/**").permitAll().anyRequest().authenticated().and()
/** other stuffs **/
}
#RestController
#RequestMapping(value="/public")
public class PublicRestController {
#Autowired private DataRepository data;
#RequestMapping(value = "/data/",method = RequestMethod.GET)
public Model getModelData(){
/** Do what you need here **/
}
}
So, all you have to do is build a REST Controller to match your URL and you are done.
And as you suggested, use #Autowired to expose only the code that you need. So you can put all your login on service/component beans and serve them as needed.

Custom nested actuator endpoint

Using Spring Boot 1.0, I was able to customize the actuator endpoints as follows...
endpoints.beans.id=foo/springbeans
This would expose the spring beans endpoint at /foo/springbeans. However, in the latest Spring Boot this is not possible due to the following code in the AbstractEndpoint...
#NotNull
#Pattern(regexp = "\\w+", message = "ID must only contains letters, numbers and '_'")
private String id;
I tried using the underscore, but that just exposes the endpoint at /foo_springbeans. This lead me to try to add a view controller so I could at least redirect or forward to the default endpoint, but I couldn't find an easy way to do that either. How can I configure the endpoint or a redirect?
After opening an issue with Spring Boot and being told to simply move the entire management context as suggested by Rafal, I was able to achieve what I was looking for, albeit with more code than I'd like. I created a custom MvcEndpoint as follows...
#Named
public class MyCustomHealthCheck extends EndpointMvcAdapter {
private HealthEndpoint delegate;
#Inject
public MyCustomHealthCheck(HealthEndpoint delegate) {
super(delegate);
this.delegate = delegate;
}
#ResponseBody
#RequestMapping(value = "/springbeans", method = GET)
public Health foo() {
return delegate.invoke();
}
}
The code above creates the /springbeans path underwhatever path the HealthEndpoint is mapped to, which is fine enough for my usecase. If I wanted it mapped to an entirely separate path, I would have needed to create a dummy endpoint and stick this MvcEndpoint under that.
For Spring 1.x Following property should help you:
endpoints.beans.path: /foo/springbeans
You can use it with any standard endpoint and if you want to use it with custom endpoint that extends AbstractEndpoint then you need additional annotation:
#ConfigurationProperties(prefix = "endpoints.customEndpoint")
and then use property:
endpoints.customEndpoint.path: /custom/endpoint

Is there an equivalent of a "beforeHandler" for spring 4?

I have a controller with a requestmapping..
#Controller
public class TestController {
private static final String template = "Hello there, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/hello")
public #ResponseBody String hello() {
return "Hello";
}
}
How can I make it such that everytime a user goes to a RequestMapping, or whichever url, some other method is called to println to the console the URL the user is at before it actually enters the method "hello"?
I would like to use this method to ensure users have proper credentials in the future. I see there are #PreAuthorize annotation, but there doesnt seem to be a method associated with it that I can write my own logic, i.e. do a simple println to the console with the current URL the user is at.
You have a number of options.
With Spring, you can implement and register a HandlerInterceptor and implement its preHandle method to log the request URL, which you can reconstruct with the various HttpServletRequest methods.
With pure servlet-api, you can implement and register your own Filter which logs the request URL and then continues the chain, with doFilter(..).
You can also use AOP, advise all your #RequestMapping annotated methods with a #Before advice that logs the URL.

can't store parameter in session (Spring MVC)

I have the following problem with annotation based Spring MVC:
I have two Controllers (LoginController, AdminController) and I can pass an object (loggedInUser of type BonjourUser) form the LoginController to the AdminController by persisting it in the session. So far so good.
To prevent hotlinking, on the initial "GET" the AdminController verifies it received a valid admin-user when it is called.
This works fine the first Time, because the loginController added the object to the session.
Now here comes my problem:
Once the admin has logged in and tries to reaccess the admin-page (eg via a link in the JSP) the user-object seems to have vanished from the session, for I get a HttpSessionRequiredException for the "loggedInUser" attribute.
AFAIK the object should not be removed from the session unless I call setComplete() on the session. (I am not calling this method!) So why is the attribute removed from the session? I read here that you cannot pass session attribues between controllers. But then here it is said that it is possible. I also think it should work, since I already pass a parameter between controllers, when I redirect from the LoginController to the AdminController.
So here is the code:
LoginController:
#Controller
#SessionAttributes("loggedInUser")
public class LoginController extends BonjourController
{
[...]
#RequestMapping(value = {"/home"}, method = RequestMethod.POST)
public String validate(#ModelAttribute(value = "command") BonjourUser user, ModelMap map, HttpSession session)
{
[...]
map.addAttribute("loggedInUser", loggedInUser);
[...]
return "redirect:/admin";
}
}
And the AdminController:
#Controller
#RequestMapping(value = "/admin")
#SessionAttributes("loggedInUser")
public class AdminController extends BonjourController
{
#RequestMapping(method = RequestMethod.GET)
public String loginAdmin(#ModelAttribute("loggedInUser") BonjourUser loggedInUser, ModelMap map, HttpSession session)
{
//check if access is authorized
if(loggedInUser == null)
{
return "redirect:/login";
}
[...]
}
}
The link I use in the admins' jsp (which leads to the exception) looks like this
Once more to admin section
Basicaly I get the same exception when I just enter this in my browsers URL-bar:
http://localhost:8080/Bonjour/admin
The exception looks like this:
org.springframework.web.HttpSessionRequiredException: Expected session attribute 'loggedInUser'
So what do I need to change to ensure the user-object (loggedInUser) is not removed from the session?
Thanks in advance,
Maex
Update Spring to the latest version and it should work. See the comment to this answer: https://stackoverflow.com/a/9412890/1981720
I tried 3 different versions of spring now:
3.1.1
3.2.2
3.2.3
Always the same problem. The debugger tells me this:
I pass from login to admin:
object is perfectly stored in the session -> attributes map.
I use a link or re-type the url to access the same page again:
no object any more in session -> attributes map.
My bad - I blocked cookies!
So the session had no chance to be persisted except for POST requests, therefor the login worked but the GET for the same page did not...

Resources