I am working on a web application.In this application I have used GWT2.3.
Now my question is about session in the client side.
In client side I have maintained session like below
public class WorkFlowSessionFactory {
private static HashMap session;
private WorkFlowSessionFactory() {
}
public static HashMap getClientSessionInstance() {
if (session == null) {
session = new HashMap();
}
return session;
}
public static Object getValue(WorkFlowSesisonKey key) {
return getClientSessionInstance().get(key);
}
public static void putValue(WorkFlowSesisonKey key, Object value) {
getClientSessionInstance().put(key, value);
}
public static void remove(WorkFlowSesisonKey key)
{
getClientSessionInstance().remove(key);
}
public static void resetSessionUser(User user) {
session.remove(WorkFlowSesisonKey.LOGGEDIN_USER);
session.put(WorkFlowSesisonKey.LOGGEDIN_USER, user);
}
}
Now after login successfully I put logged in user in client session as well as server side
session like below
session.put(WorkFlowSesisonKey.LOGGEDIN_USER, user);
Now when I refresh browser I session instance went null.And all the session variable also null.
One way in my mind is on refresh first I make a server hit to get a logged in user and again set
client side session logged in user. So at many places at client side where logged in user required
it will work after the refresh of browser.
But I am not sure it is a right way to do or not.
So please suggest me this case, is there any good way to do this ?
Thanks in advance
Yes, accessing the server and querying if the user is logged is a viable solution. I can think of following solutions:
In the onModuleLoad() method access the server and check if the user is still logged in and store the session in your client session (as you suggested it).
Store your session in a non volatile storage (Cookie or HTML5 localstorage). However make sure that you don't store any passwords or sensitive data. Store a hash or unique identifier for your session.
In any case make sure that you read and understand about security in GWT apps.
Here are two good ressources: Loginsecurity and Security for GWT applications.
The important rule is to never trust the client. Always check permission and credentials on the backend.
Related
We are using shiro in our application, and the session are saved in the database for scale. And we have our own accounts databse, so far so good.
This is the core security components:
DatabaseRealm
Vvalidate user by UsernameAndPasswordToken and the password in the database, retrieve the permissions fro the database.
DatabaseSessionDao
Extends the CachingSessionDAO, for create,read,delete sessions from the database.
DefaultWebSessionManager
Shiro built in components.
Now we have to make two kinds of improvement:
Integrate the OAuth login
For example, user should be able to login by Google or Facebook or their own accounts registered in our application.
Then I wonder how can we re-use the existed security components like the DatabaseRealm, since the realm will check the AuthenticationInfo's credentials which is not avaiable in the OAuth context:
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
SimpleAuthenticationInfo info = null;
if (token instanceof UsernamePasswordToken) {
UsernamePasswordToken uToken = (UsernamePasswordToken) token;
User user = queryUserByName(uToken.getUsername());
info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword().toCharArray(), getName());
if (user.getSalt() != null) {
info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
}
} else if (token instanceof OAuthUserToken) {
OAuthUserToken oToken = (OAuthUserToken) token;
String type = oToken.getOauthType();
String openId = oToken.getOpenID();
//then what should I do to make the `Credentials` check passed?
}
return info;
}
How to fix this?
Using JWT(Json Web Token)
The sessions are saved to the database for cluster deployment at the moment, however we found that it may slow our response, also we need to provide api for the mobile paltform, so we try to use JWT.
While it seems that shior use cookie + session to identify if user have been authenciated or not. I have no idea how to replace that.
Any suggestions?
It may be better to add new Realm / Filter / Login url for redirection.
GoogleRealm
public class GoogleOAuthRealm extends AuthorizingRealm {
...
public GoogleOAuthRealm() {
//OauthToken implements AuthenticationToken to hold code
setAuthenticationTokenClass(OauthToken.class);
}
...
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
OauthToken tk = (OauthToken) token;
String authCode = (String) tk.getPrincipal();
//1. fetch token by posting code to google
//2. validation & parse token
//org.apache.shiro.authz.SimpleAuthorizationInfo
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();
//set permission manually
return info;
}
...
}
config GoogleRealm in securityManager, and redirect to a new url after google login success.
public class GoogleAuthenticatingFilter extends FormAuthenticationFilter
<property name="filterChainDefinitions">
<value>
...
/login/googleLogin = GoogleAuthenticatingFilter
...
</value>
</property>
As neuo wrote above, use a different realm for OAuth and then do some wiring up on the back end to reconcile the user credentials. For your scaling and performance, I’d suggest using something like Redis as a session cache - that will save you having to persist sessions in the database.
Re-Using Existing Components
Consider the construct in which you are working, you probably do not want to reuse the DatabaseRealm for other authentication schemes. Rather create individual realms for Google, Facebook, etc.
This way you will be able to control what AuthenticationTokenand AuthenticationInfo will be used in each Realm.
JWT/Cookie Session
From what you decribe I think you would likely want to create a RESTful API for your mobile platform. The REST spec requires that the server does not maintain, and more importantly not rely on server-side state.
Fortunately shiro allows you to configure endpoints that do not create a session when a request is received. More details on session management here
Considering the above, session tracking becomes irrelevant, and you could use the JWT token as a form of Bearer token to tacitly authenticate the user on every request. Be sure to consider the security short-falls of the Bearer token, which may be mitigated by always using an encrypted connection.
I use Spring 4.1.1. And I must make service of user session. What's the best way of storing session related data of a user? I read so many way's , but I don't understand which way is proper?
it's example that I need
#Controller
#SessionAttributes("user")
public class PagesController {
#RequestMapping(value="/sign_in", method = RequestMethod.POST)
public String getSignIn(#RequestParam(value="user")String user ,
#RequestParam(value="pass")String password,
Model model) {
UserDAO dao = new UserDao();
if(dao.isUserValid(user,password) && !model.containsAttribute("user")){
User user = new User();
model.addAttribute("user",user);
return USER_PAGE;
}
return LOGIN_PAGE;
}
}
First of all, Session Attribute is not a good option to store your user object. It is spring who decides when to clear a session attribute data. As per spring documentation, spring removes a session attribute when it understands that a 'conversation' is completed. You only use session attribute when you are in a controller scope and the data is temporarily needed to be stored in the session.
As far as user login object goes, the thing you need to do is to use http sesison. When you login/sign in to your application you actually post the login credential to your controller. Once validated, you put the user object (with your necessary info-as less as possible- in to an object and store in to your session). This object will remain as long as it doesn't expire or you clear it when the user trigger logout.
Moreover if you still want to use SessionAttribute to store your user Object. Then there can be further problem when you deploy your application to a clustered environment. Your session will have to be copied to each instance of your server unless you implement sticky session. Copying httpsession is the simplest of task whereas copying the same instance of a sessionAttribute is not.
#RequestMapping(value = "login.html", method = RequestMethod.POST)
public ModelAndView post(#ModelAttribute("login") LoginEntity login, HttpServletRequest req) {
... process the data ...
if passed put it into session:
HttpSession session = req.getSession(true);
UserObject userObject=new UserObject();
userObject.setName(login.getUserName());
...
session.setAttribute("user",userObject);
It is OK that you put your user object in session, and then use it in your project everywhere. However, if you get a lot of users, that means you have many user object in the memory of your server. The memory might run out.
Another way to do it is to put some user information in cookies with some encryption and validation, but just remember not to put too much info in cookies because cookies will be sent every time a request or a response is made. If there to much information to send, it will slow the response time.
And just a reminder, you should call status.setComplete() to clean the attributes inside a session when they are not needed.
Does SessionStatus object.setComplete() clears all the session attributes or just work for the controller in which it is used?
and if you don't know how to use it, you can see the article below
http://vard-lokkur.blogspot.tw/2011/01/spring-mvc-session-attributes-handling.html
I'm trying to figure out a good way to organize a javax.websocket multiplayer card game I'm working on.
I want to split up my code into multiple classes which are each a ServerEndpoint. My problem is that I need an effective way of sharing session data between them.
I have an index at "/index", which is where I'm currently creating Player objects for clients. I'm setting these like so:
#ServerEndpoint("/index")
public class IndexEndpoint {
#OnOpen
public void openConnection(Session session) {
session.getUserProperties().put("player", new Player());
}
}
And that works; I can access the Player objects elsewhere throughout IndexEndpoint.
But when I try to access the user properties from another endpoint (after having established a connection with IndexEndpoint in JavaScript, waiting 5 seconds and then opening up an additional connection to LobbyEndpoint on the same page), I get null.
#ServerEndpoint("/lobby")
public class LobbyEndpoint {
#OnOpen
public void openConnection(Session session) {
System.out.println(session.getUserProperties().get("player")); // prints null
}
}
Which leads me to imply that session data is unfortunately not shared across endpoints.
Is there any good way for me to share websocket session data across multiple classes?
I guess one solution would be to just have one über endpoint for all users to connect to, and which can handle any message type. Then that endpoint delegates message data to other parts of my application.
However I feel like this design would be very messy and restrictive. I'd like to have endpoints dedicated to specific rooms, using annotations like #ServerEndpoint("/rooms/{room-id}") and #PathParam("room-id"). So if I was using a monolithic Endpoint then I couldn't do that; I wouldn't be able to know if a connecting user is a user who access to the room.
what about a singleton EJB containing all player and game data?
#Stateless
#ServerEndpoint("/lobby/{sessionKey}")
public class IndexEndpoint {
#EJB
GameData data;
#OnOpen
public void onOpen(Session session, EndpointConfig config,
#PathParam("sessionKey") int id) {
Player player = data.getPlayer(id);
session.getUserProperties().put("player", player);
}
}
The first message from the IndexEndpoint could provide the client with its id and then the client could provide its id to the LobbyEndpoint in the ws URL (or in a header with a Configurator), that is how I plan to do it.
I am working on struts2. I use below code to check if the User have logged in or not
public String execute()
{
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession(false);
System.out.println(session);
if(session == null)
{
return "UserLoggedIn";
}
return "success";
}
When I access print the session value in console first time it print null. But when I do the same thing by refreshing the page it prints some thing like below and its ends up letting the user to access the page with out logging in.
org.apache.catalina.session.StandardSessionFacade#16f21478
How to carry out session checking to see whether user logged in or not.
Thank you very much.
Well if you are just doing this for learning purpose, i believe its better to store a variable in session, once user logged in.
Say, when use click login button and if credentials provided by user are correct you can store a variable (logged-in) in to session and on clicking log-out button can clear this variable.
However there are few more things you need to take care.
Its better to use SessionAware interface provided by Struts2 which is a clean way to inject Session as Map in you action class.
public class YouAction implements SessionAware{
private Map<String, Object> sessionMap;
#Override
public void setSession(Map<String, Object> sessionMap) {
this.sessionMap = sessionMap;
}
}
Above way let you action independent from direct dependencies from HTTP objects, which can be helpful in unit testing.
If you have the option can use Spring security which is a much better way to handle User authentication and Authorization process.
When user logged in put a variable in session.When logout clear that one from session.
Then check that variable in session .
I have a web based application that uses userName and password for login.
now how can i check on certain time which all users are logged in at that very time.
i am using session management and no DB is used in application everything is on filesystem
Edit: 1 more silly doubt.. how to define a variable with application scope.. is this something of this sort?
<env-entry>
<env-entry-name>test/MyEnv2</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>true</env-entry-value>
</env-entry>
Just collect all logged in users in a Set in the application scope. If your application is well designed, you should have a javabean User which represents the logged-in user. Let it implement HttpSessionBindingListener and add/remove the user from the Set when it's about to be bound/unbound in the session.
Kickoff example:
public class User implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.add(this);
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(this);
}
// #Override equals() and hashCode() as well!
}
Note that you need to prepare the Set in the application scope so that it doesn't return null in above methods. You could do that in the same methods by a nullcheck, or with help of ServletContextListener#contextInitialized().
Then, anywhere in your application where you've access to the ServletContext, like in a servlet, you can just access the logged-in users as follows:
Set<User> logins = (Set<User>) getServletContext().getAttribute("logins");
Update
BalusC's approch is more suitable, here by this approach you will get no of session not logged in Users. to do that you need to track HttpSessionBindingListener .
You can implement HttpSessionListener and can track the logged in users
public void sessionCreated(HttpSessionEvent se) {
// adding logging in user to some application data map or inserting it to DB
}
public void sessionDestroyed(HttpSessionEvent se) {
// remove logged in user to some application data map or inserting it to DB
}
A more scaleable solution would be to add a column like "loggedIn" to your users table in the database and set it to true when you log a user in. This would take bloat off the application server and also support a distributed environment if your application needs to run more than one box in the future.