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.
Related
I have a web application written in Java using the Spring framework.
I would like to store the users activities like, page visits, actions, interactions etc.
I read that usually this is done by creating a table for each tracked aspect. I was wondering if there is a better way to do it using Spring framework, like a way to intercept all the requests and trigger some actions.
What kind of technology do you recommend to store all these information? Right know I’m using a MySql database interacting with it through JPA. But, since I’m really really new to these kind of things I don’t know if I should go with a NoSql database or stay with my already existing MySql database. This wonder comes from the idea that this kind of data flow will be much bigger than a normal data flow coming from more traditional actions such as signin, creation, deletion etc.
Hope to have explained myself... if not just tell me and I’ll try to add more details.
[EDIT 1]
The web app is an e-commerce. So far it does not have So many users but it will (in the order of thousands).
The goal of the user tracking it’s just to profile them in order to give them a better and more custom service. For instance, if a see that a user is taking a look to a lot of items of a precise category I can show him more items of that kind.
I do no care that much about the performance, I mean, it does not have to be so fast.
Right know I have just one database and everything is stored inside it. I don’t know if charging it with this kind of data flow would slow down its performance.
The application is running on AWS ElasticBeanstalk and the database is on AWS RDS.
In general its a very broad topic.
The following considerations come to my mind:
How many requests pass to the microservice per some period of time? If its a small number of users (which translates to the number of records to the database) - then its ok to go with the MySQL approach - the table won't be large. Note however, that sometimes it should be cleaned anyway
Is the latency important? Sometimes requests have to be served very quickly, adding a hop to the database to save the user preference can be problematic
How do you want to consume this kind of information? Are you planning to use dashboards (in this case micrometer + Prometheus / InfluxDB and Grafana can be a good solution). Are you planning to actually charge the users per number of requests with an ability to send the monthly bill to their email in PDF or provide a web access to such an information (like AWS does for example)?
How about Rate limiter? Are you planning to deny some requests if they're frequent and coming from the same user?
How many instance will "add" this kind of information? What if you have thousands of microservices that now will have to write to MySQL - it might not survive such a load (in addition to the regular load its set up for)?
The range of solutions can vary.
You can Batch the requests per user in memory and send once in while a message into Kafka and then use kafka streams to provide aggregations on it. With this approach you'll minimize the impact of the added processing on the existing solution and will deploy some other service that will be able to process this pretty large amount of data.
Another option: maybe you can create an asynchronously populated log file and store the information there. Then you might want to add some "agent" / side-car container like logstash and stream the data into some storage. Yet Another project that might be relevant in this field is Apache Flume which will allow you to construct a pipeline.
For billing you might use specialized systems AFAIK spring doesn't have anything like this usually these are ready products that you can integrate with.
For Rate Limiting you might consider: Resilience4j or solve it with redis
Yeah , That's possible , Here below are the three approaches with some sample snippets which would help you in the implementation , Moreover it depends on the data you store when you log the activity and when do you consider the activity data as obsolete and there are many factors which can decides your data store.
Approach 1: You can keep track of the login user using Spring-Security
You can write a HTTPSessionBindingListener and track the actions something like this
#Component
public class LoggedUser implements HttpSessionBindingListener {
private String username;
private ActiveUserStore activeUserStore;
public LoggedUser(String username, ActiveUserStore activeUserStore) {
this.username = username;
this.activeUserStore = activeUserStore;
}
public LoggedUser() {}
#Override
public void valueBound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
users.add(user.getUsername());
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (users.contains(user.getUsername())) {
users.remove(user.getUsername());
}
}
// standard getter and setter
}
and for login and logout you can track using AuthenticationSuccessHandler
#Component("myAuthenticationSuccessHandler")
public class MySimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Autowired
ActiveUserStore activeUserStore;
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
HttpSession session = request.getSession(false);
if (session != null) {
LoggedUser user = new LoggedUser(authentication.getName(), activeUserStore);
session.setAttribute("user", user);
}
}
}
Approach 2 : The other method if you want to make it very simple is that you can write a OncePerRequestFilter
#Component
#Ordered(Ordered.LOWEST_PRECEDENCE)
public class LogFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Log the info you need
// ...
filterChain.doFilter(request, response);
}
}
Approach 3 : Implement using Spring AOP.
#Aspect
#Component
public class WebMethodAuditor {
protected final Log logger = LogFactory.getLog(getClass());
public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
#Autowired
AuditRecordDAO auditRecordDAO;
#Before("execution(* com.mycontrollers.*.*(..))")
public void beforeWebMethodExecution(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
User principal = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Timestamp timestamp = new Timestamp(new java.util.Date().getTime());
// only log those methods called by an end user
if(principal.getUsername() != null) {
for(Object o : args) {
Boolean doInspect = true;
if(o instanceof ServletRequestDataBinder) doInspect = false;
if(o instanceof ExtendedModelMap) doInspect = false;
if(doInspect) {
if(o instanceof BaseForm ) {
// only show form objects
AuditRecord ar = new AuditRecord();
ar.setUsername(principal.getUsername());
ar.setClazz(o.getClass().getCanonicalName());
ar.setMethod(methodName);
ar.setAsString(o.toString());
ar.setAudit_timestamp(timestamp);
auditRecordDAO.save(ar);
}
}
}
}
}
}
Source and More details :
https://www.baeldung.com/spring-security-track-logged-in-users
Spring / AOP: Best way to implement an activities log in the database
What is the best way to log Activity in Spring Boot with Thymeleaf?
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 .
In our Java based web application we have the concept of Roles and Users. Basically we have many links in our page, and these links can be accessed based on the Role assigned to the user.The Roles and User related information is stored in DB.
During the User Login time we query the DB, get all the related roles and display only the links that are assigned to his Roles. So the user can see only the links he has access.
This way is Working Very Weel. But every time user login the program checks his role level from database.this is burden to database. Please suggest another ways we prevent the accessing multiple links in Web Application.
2 options:
1) Put the user roles in the session when he is authenticated for the first time and access the session everytime he tries to access a functionality
2) Use a Map<String, List<Role>> as a cache and access this map instead of the Database for authenticating a user. Key of the map can be the username. When the user logs in, add the user to the map. When the user logs out or the session expires, remove from the map. Spring Security uses Ehcache for caching so you could do the same.
public void doLogin(HttpSevletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = service.authenticate(username, password);
HttpSession session = request.getSession();
session.setAttribute("roles", user.getRoles());
}
public void save(HttpServletRequest request) {
List<Role> roles = request.getSession().getAttribute("roles");
for(Role role : roles) {
if(role.getName()=="save") {
service.save();
break;
}
}
}
A trivial example added. For the cache, it'll be a similar except instead of session use Map.
I am building a struts 2 application with JPA. A user can login into the application multiple times. I want
user to be able to view all his session in a grid and probably highlight the current session and optionally the user can select a session and terminate it.
An administrator should also be able to see all the logged in users and can also view all the sessions of each logged in user and also can optionally terminate any of the sessions.
Thanks
I think HttpSessionBindingListener is what are you looking for.
I won't write down the complete code, just suggest you a way you can do it:
You can add a static field (Map) to your User class (DTO) where you will store all active sessions of users. :
e.g private static Map<User, HttpSession> usersSessions= new HashMap<User, HttpSession>();
Then make User class implemets HttpSessionBindingListener. This way you can specify valueBound(HttpSessionBindingEvent event) method in which you can grab actually created session and put it into your usersSessions like this :
usersSessions.put(this, event.getSession());
In valueUnbound(HttpSessionBindingEvent event) method then :
usersSessions.remove(this); to remove users session after logout.
This way you have Map of all of your active sessions also with information to which user it belongs to. IMO you can figure out your other problems easily with this.
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.