I am coming to Java from Rails and PHP, so my thinking here may be tainted.
I would like to implement a login system similar to ones I have done in my other systems (I understand you can manage login etc using the built in properties of Java EE, I just want to understand how I could do this manually and share objects amongst beans.)
With rails or php it is easy to maintain a session variable that holds the id of a logged in user. Then a global variable in PHP, or a property on the applicationController in rails can be pre-loaded with the user object, enabling it be available in all controllers/pages. That way the logged in status of the user and other parameters are easily accessible to all pages/controllers.
I don't know how to do a similar thing using JSF.
I know how to build a user object using JPA, and then create a managed bean with session scope that holds a reference to the user object after logging in using a loggin method from a login form. That part I understand:
#ManagedBean
#SessionScope
public class LogginController {
// inject persistence context, or use EJB to do actual loading etc
private User currentUser; //JPA Entity
void loginAction() {
// action from login form
// authenticates user and loads user object into currentUser property
Where I get stuck, is that although the managed bean that contains the currentUser property has session scope, how would I access that property in other managed beans to get the current user? Managed beans seem to exist in isolation from each other.
Is the following code acceptable?
#ManagedBean
public class SomeOtherBean {
#ManagedProperty
LoginController loginController;
public void someOtherMethod() {
User myUser = loginController.getCurrentUser();
//
// etc
Would the class having the bean injected also have to have SessionScope too?
Is this the wrong approach, would I need to manually set the session using the underlying ServletContext so that the user was accessible in other beans (i.e. save the id of the logged in user in the session, and then reload the user after accessing the user id session variable in different beans)?
Am I going about this all wrong? Is there an easier way I am missing.
Is the following code acceptable?
Yes (assuming that it's pseudo; in real code it should be a private property and you should specify the managed property value like so #ManagedProperty("#{loginController}") and provide at least a setter method).
Would the class having the bean injected also have to have SessionScope too?
Not necessarily. It can perfectly be a request or view scoped bean, but not an application scoped bean (it would result in an exception). At least, you should be very careful with choosing the bean scope. Do not choose a too broad scope for the data it holds. See also How to choose the right bean scope?.
Related
I have a question that, i have a spring-mvc based project which is accessible by multiple user. My question is that when more than one user access that application then for each user there is separate controller class object or all user access the same controller class object.
There will be multiple controller instances for different requests.
Please read:
http://docs.spring.io/spring-framework/docs/2.5.x/reference/mvc.html
Related answer:
How does Spring MVC handle multiple users
If the controller is a bean (which is the usual case) then the default is one bean per Spring container context.
If you set the controller/bean to scope=prototype then you would get a new instance from the factory each time.
I have the following session scoped bean:
#ManagedBean
#Component
#Scope(proxyMode= ScopedProxyMode.TARGET_CLASS, value="session")
public class SessionData implements Serializable {}
and I store tomcat sessions in a database. The problem is that, when the application tries to deserialize a stored session, I receive the following error:
org.apache.catalina.session.PersistentManagerBase.swapIn Error deserializing Session EE913D2ACAD49EB55EDA657A54DFA2CB: {1}
java.lang.ClassNotFoundException: de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9
It seems that it serialized actually the whole Spring context, and obviously there is no such class de.myproject.SessionData$$EnhancerBySpringCGLIB$$768b59b9 after server restarts, so I receive the aforementioned exception.
Is there a way to avoid this, so that the session-scoped bean is serialized properly?
UPDATE: There is an issue regards this which marked as resolved without comments, however I still face it.
Please have a try:
using: import org.springframework.test.util.AopTestUtils;
Serializable readyToSerialize = AopTestUtils.getUltimateTargetObject(yourInstance);
before serialize it.
Note: this code is usefull to understund the problem, if this work, you have to analyze the project architecture and dependecies, to better accomplish for production code. First of all, why you need to serialize a ScopedProxyMode.TARGET_CLASS
Having a bean with a scope session doesn't mean that the bean is serializable and that it can be stored in a session.
As you can guess from the name of the class, a proxy class is generated at runtime with a different name at each startup. This explains why a problem occurs at deserialization.
I guess you try to add this SessionData as an attribute of the web session. You should not. Store your POJO data in the web session without using beans.
If you use the bean to inject database connections or similar objects, forget it. You can just use session scope beans for particular contexts which don't feet your requirements I guess.
i don't know well the your task, but in my opinion a data object like this should not be a spring bean because spring bean should be business logic bean, controller bean and so on and not session dto.
for this reason i consider thag you should try to think why you want store the data of your spring bean, and try to decopled the data that you want in http session, #sessionattribute of springmvc,from the business logic bean that shoud nor be session aware.
i hooe that this can help you to change your implementation stategy in order to find the solution of your problem
I was creating my first application using Apache wicket and am stuck on a problem. After the user logs in through the authentication method I have a new session which is created for that user. Now if I wanted to have data stored for just that user how would I use bean to implement that?
At the moment i created an interface and a class with get and set methods for the variables i wanted stored and created a bean such as <bean id="springApplicationContext" class="com..util.SpringApplicationContext"/> but what happens is the data gets overwritten but when i change the scope to "session" everyone has the same data in the bean still.
Thanks
The correct way is to use Session scoped Spring bean. There must be some error in your config if the data is visible to all users.
Using Spring has nothing to do with Wicket though!
Alternative approach is to store your data in Wicket's Session class.
Override MyApplication#newSession() method and return MySession class. The instance of MySession will be stored as an attribute in the HTTP session by Wicket. You can put any member fields inside MySession, e.g.;
public class MySession extends WebSession {
...
private MyBean myBean;
// setter and getter
...
}
Then in your Wicket code use it with: MySession.get().getMyBean().setSome(thing);
I've a doubt about Spring session bean. Let me try to explain what I need and what I did. I need to store on a session variable (in that case a Bean) the user_id so, when I need to create some record on db I can keep track of who did what.
To do that, for first, I created a bean and, second, I modified my application context in that way:
<bean id="UserInfo" class="net.agdev.session.UserInfo" scope="session">
<aop:scoped-proxy/>
</bean>
I read that using this :
ContextLoader.getCurrentWebApplicationContext().getBean("UserInfo");
is ppossible to access to the bean, but it's not yet clear how to fill that bean..
I tryed to read on Spring documentation how to initalize the bean and how to recall on my Class controller but I didn't find anything.
Could you suggest where to find an example or a tutorial to do that?
many thanks!
Andrea
You mean how to get the user_id into the session bean? Depending on your application this should probably happen right after the user "logged in". Meaning, if you for instance have a login webflow or controller, set the user_id in your session bean within that webflow or controller.
So if I understood your context correctly this has only very little to do with Spring itself and mostly with your application :-)
If you want other aspects of your bean initialized for instance from operations on other services you could set an init-method on the bean definition as detailed here.
By aspect programming like AspectJ. You have to set some trigger, for example after an user does something you have to read your bean and fill it the operation info that have been performed by the user.
You can use #annotation to define trigger or you can do it by spring xml file. I think you have to use an application context bean and not a session bean.
Here we have a Spring based webapp in google apps engine.
I've created a UserDetailService class to load the UserDetails from the GAE data store (assuming this is the best approach).
#Service("springUserDetailsService")
public class SpringUserDetailsService implements UserDetailsService {
#Resource(name="userDao")
private IUserDao userDao;
//...
But GAE throws the following exception (apparently) when it tries to persist the session to the data store.
java.lang.RuntimeException: java.io.NotSerializableException: com.prepayproxy.servicelayer.SpringUserDetailsService
at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java:387)
at com.google.apphosting.runtime.jetty.SessionManager.createEntityForSession(SessionManager.java:364)
I first thought to Serialize the SprintUserDetailsService object, but it has a reference to my UserDao, which in turn has references to data source objects, at about that point I freaked out and decided to see if there's a better approach.
On your second point, I am only assuming that spring security is storing a reference to the UserDetailsService in the session, which is how it gets tied up with the GAE serialization of the session. All beyond my control as far as I see unless I missed something.
There's no reason for SpringSecurity to put a reference to your application's UserDetailsStore into the session. A UserDetailsStore is not conceptually session scoped.
If the session manager is trying to serialize a UserDetailsService, it is probably a result of a reference to the UserDetailsService in some other session scoped object.
Two options:
don't worry about the DataSource - spring, since version 3, serves a proxy which, when deserialized, gets a fresh data source, rather than the original (which is not relevant)
don't put your service in the session. Perhaps it is referenced by something that is in session scope, so make it volatile there.
See also this question