How can i access session scoped variable in spring interceptor?
Session scoped class:
#Component
#Scope("session")
public class User {
}
Controller:
#Controller
#RequestMapping("/restricted")
#Scope("request")
public class RestrictedController {
#Autowired
private User user;
}
Dispatcher servlet:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/restricted/*"/>
<bean class="com.interceptors.RestrictedInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Interceptor class:
public class RestrictedInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
}
}
In prehandle i want to check if user is logged in (some other checks as well), how can i access session scoped user variable here? Autowiring user in Interceptor class throws exception.
You should be able to access your session-scoped user using the following code:
request.getSession().getAttribute("scopedTarget.user");
See related post here and org.springframework.aop.scope.ScopedProxyUtils class.
Related
I have a kind of online store in Spring. I want to create a shopping cart for each new user who visits the site and stored it in the session. How can this be done? It's just that I've never worked with sessions in Spring. Perhaps there is a good resource to study this stuff.
#Controller
class example{
#RequestMapping("/")
public String test(HttpSession session){
session.addAttribute("cart",new Cart());
}
}
Make your controller session scoped
#Controller
#Scope("session")
then add one attribute to session
#RequestMapping(method = RequestMethod.GET)
public String testMestod(HttpServletRequest request){
ShoppingCart cart = (ShoppingCart)request.getSession().setAttribute("cart",valueOfCart);
return "testJsp";
}
then Scope the user object that should be in session every time:
#Component
#Scope("session")
public class User
{
String user;
/*getter setter*/
}
then inject class in each controller that you want
#Autowired
private User user
The AOP proxy injection : in spring -xml:
<bean id="user" class="com.User" scope="session">
<aop:scoped-proxy/>
</bean>
refer:How to use Session attributes in Spring-mvc
In spring-mvc.xml:
<beans ...>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.app.controllers.ExceptionController"/>
....
</beans>
In GlobalException.java:
#ControllerAdvice(basePackages = "com.exceptions")
public class GlobalException {
#ExceptionHandler(UserDefinedException.class)
public ModelAndView processCustomException(UserDefinedException ud) {
ModelAndView mav = new ModelAndView("exceptionPage");
mav.addObject("name", ud.getName());
mav.addObject("message", ud.getMessage());
return mav;
}
}
In ExceptionController.java:
public class ExceptionController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
throw new UserDefinedException("Custom Exception has occured", "CustomException");
}
}
Ecxception is throwing as com.exceptions.UserDefinedException: Custom Exception has occured. But ExceptionHandler method is not called. Whats wrong is this code. I'm using spring 4.3 version.
enable Spring's component scanning in your spring-mvc.xml by adding this:
<context:component-scan base-package="com.exceptions" />
and remove your obsolete XML configured Spring bean (<bean class="com.app.controllers.ExceptionController"/>)
also annotate your controller classes with #Controller and add a #RequestMapping to your controller methods, e.g. like this:
#Controller
public class ExceptionController {
#RequestMapping(value="/whatever", method=RequestMethod.GET)
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
throw new UserDefinedException("Custom Exception has occured", "CustomException");
}
}
this way, your classes annotated with Spring stereotype annotations (#Component, #Service, #Controller, #Repository) should be found, instantiated and registered as Spring beans by Spring itself at application startup!
I am trying to create custom "userContext" as a SpringBean with request scope but I am unable to do so. Basically I have a Jersey REST api and I want to do authentication and authorization using my custom filters in which I autowire my "userContext" bean. The process looks like this:
REST API called (I expect Spring to create new instance of userContext bean)
AuthenticationFilter autowires new instance of userBean and populates it
AuthorizationFilter autowires the same instance which is populated now and authorize the user
When i first call the REST api (after server restart), it works as expected, but any other call fails, because AutorizationFilter gets an empty instance of userBean. I expect some fundamental misunderstanding of scopes on my part.
Btw: I'd like to avoid using ThreadLocal directly since Request scope should take care of it
I would like to know, why authorizationFilter doesn't see the populated version of the userBean and why the first call works. Thanks in advance for any help.
Just some parts of the code:
#Secured({Role.ADMIN}) //custom annotation
#GET
#Path("{id}")
public Response getUserById(#PathParam("id") Long id) throws IOException, MainException {
#Secured //custom annotation
#Provider
#Priority(Priorities.AUTHENTICATION)
#Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class AuthenticationFilter implements ContainerRequestFilter
#Autowired
private User userContext;
#Secured //custom annotation
#Provider
#Priority(Priorities.AUTHORIZATION)
#Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS)
public class AuthorizationFilter implements ContainerRequestFilter {
#Autowired
private User userContext;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class User extends ModelBase implements Serializable {
Since Providers are not request scoped, I had to inject whole ApplicationContext so I could directly modify the right instance of userContext bean (which is request scoped). Basically I did something like this in both filters:
#Autowired
private ApplicationContext applicationContext;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
User userBean=applicationContext.getBean(User.class);
....
userBean.setSomething("aaa");
Then I could just autowire such bean in my REST Resources, because they are request scoped by defaul:
#Component
#Api(value="/users", description = "Endpoint for Users listing")
#Consumes({MediaType.APPLICATION_JSON, Constants.API_VERSIONS.V1_HEADER_XML, Constants.API_VERSIONS.V1_HEADER_JSON})
#Produces({MediaType.APPLICATION_JSON, Constants.API_VERSIONS.V1_HEADER_XML, Constants.API_VERSIONS.V1_HEADER_JSON})
#Path("/users")
public class UserResource {
private static final Logger logger = LoggerFactory.getLogger(UserResource.class);
#Autowired
private User authenticatedUser;
This solution should be viable and resistent against thread race conditions etc.
I am having a AuthenticationSuccessHandler which should hold a UserService. My problem is that i am getting a NullPointerException on the userService at this line:
logger.debug(userService.getAllUsers().toString());
AuthenticationSuccessHandlerImpl:
#Repository
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandlerImpl.class);
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.debug(userService.getAllUsers().toString());
response.setStatus(HttpServletResponse.SC_OK);
response.sendRedirect("index");
}
}
I Have also tried #Service and #Component Annotation but the same error.
It works in all other Services and Controller from my project but not in this Handler.
I also have this line of code in my config:
<context:component-scan base-package="com.net4you.*" />
<tx:annotation-driven />
EDIT:
AuthenticationSuccessHandlerImpl is not created with new, but with:
<security:form-login login-page="/login" default-target-url="/index" authentication-failure-url="/fail2login"
authentication-success-handler-ref="customAuthenticationSuccessHandler"/>
<beans:bean id="customAuthenticationSuccessHandler" class="com.net4you.slamanagement.helper.AuthenticationSuccessHandlerImpl"/>
Project structure:
Debugger:
1) you dont need .*
<context:component-scan base-package="com.net4you.*" />
this is enough
<context:component-scan base-package="com.net4you" />
2) are you sure that userService is null?
3) configuration looks fine, maybe getAllUsers() method is returning null,
can you show its implementation?
UPDATE
You can solve this problem in two ways
1) remove
<beans:bean id="customAuthenticationSuccessHandler" class="com.net4you.slamanagement.helper.AuthenticationSuccessHandlerImpl"/>
and annotate AuthenticationSuccessHandlerImpl like this
#Component("customAuthenticationSuccessHandler")
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandlerImpl.class);
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.debug(userService.getAllUsers().toString());
response.setStatus(HttpServletResponse.SC_OK);
response.sendRedirect("index");
}
}
2) the second way would be creating setter of userservice in AuthenticationSuccessHandlerImpl , create userservice bean in xml manually and then inject it directly using setter property of authenticationSuccessHandlerImpl in xml, this solution is more complicated and i would suggest you to use first one
Your implementation doesn't work because you define a bean in xml without setting the userservice for it (#autowired doesn't work if you define bean manually) and then you inject this bean into form-login
I'm not a Spring expert and I'm facing a behavior I don't understand...
I have a SessionAttribute "user" in my Controller, that is autowired to my bean User.
When I log in, my User is populated with some values etc.
When I log out, I am expecting that my session attribute "user" would be reset, but it keeps its values.
So where is the problem? Is my log out not working properly? Or is it normal and so, could someone explain me what is happening inside Spring please?
Here is a code Sample to understand my question:
#Controller
#SessionAttributes("user")
public class HomeController
{
#Autowired
private User user;
// Session Attribute
#ModelAttribute("user")
public User setSessionAttribute()
{
LOGGER.debug("Adding user to session...");
return user;
}
...
}
Edit: logout sample code and user declaration
My User is declared like this:
#Component
public class User
{
...
}
To log out I have a link pointing to /myapp/j_spring_security_logout and I have implemented a logout handler:
#Component
public class MyLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler
{
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException
{
//to check if user is in session, but it's not
Enumeration<String> e = request.getSession().getAttributeNames();
//some code needed to log out from my custom security manager
//kill the session (not spring session) and redirect to the specified url
agent.logout("/myapp/login");
super.onLogoutSuccess(request, response, authentication);
}
}
Now that you've posted User
#Component
public class User
{
...
}
you will notice that it is has Singleton scope. The bean autowired here
#Autowired
private User user;
is that singleton instance. It will always be the same regardless of what Session or request you're processing and regardless of you logging out. So up to now, all your users have been sharing the same User instance.
You can change it to have Session scope.
#Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
#Component
public class User
{
...
}
Now each Session will have its own instance to work with.
I believe SimpleUrlLogoutSuccessHandler is not clearing the content of the session.
SimpleUrlLogoutSuccessHandler only invokes the handle() method in AbstractAuthenticationTargetUrlRequestHandler and it's Javadoc says:
Invokes the configured RedirectStrategy with the URL returned by the determineTargetUrl method.
The redirect will not be performed if the response has already been committed.
Simplest solution would be to remove this attribute from the session by:
request.getSession().removeAttribute("user");