Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

[Spring security] Concurrency Control - Logout automatically when delete or block user using spring security


May 02, 2021 Programing language


Table of contents


Table Of Content

1. Config sessison listener point to HttpSessionEventPublisher, that is class of spring security

2. Define Session Registry bean

3. Define Concurrency Filter bean

4. Define Session Authentication Strategy bean

5. Coding future deleted or block user

Many web applications have an admin page, that manage user of system. The manager deletes an user while it's logined in, it can still perform the operations normally, so how to force blocked user to logout, this tutorial will guide you do that. Please follow the content below

This tutorial using spring security version 3.2 or later

1. Config sessison listener point to HttpSessionEventPublisher , that is class of spring security

In web.xml file add listener tag insite web-app tag

<listener>
 <listener-class>
  org.springframework.security.web.session.HttpSessionEventPublisher
 </listener-class>
</listener> 

2. Define Session Registry bean

In spring-security.xml file define bean point to SessionRegistryImpl

<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />

All sessions of web application are stored in SessionRegistry

3. Define Concurrency Filter bean

That bean is custom filter, that was created by spring security, its check sessions logined and force logout session when necessary

<beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
	<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
	<beans:constructor-arg name="expiredUrl" value="/logout" />
</beans:bean>

Line 1 : create bean with id concurrencyFilter poit to ConcurrentSessionFilter

Line 2 : Inject constructor argument for sessionRegistry variable, that referent to SessionRegistry bean was created in step 2

Line 3 : Inject constructor argument for expiredUrl variable, that is logout url when session expired

4. Define Session Authentication Strategy bean

This bean process sessions, check max sessions of each user accepted by spring security

<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
	<beans:constructor-arg>
		<beans:list>
		<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
			<beans:constructor-arg ref="sessionRegistry"/>
			<beans:property name="maximumSessions" value="5" />
			<beans:property name="exceptionIfMaximumExceeded" value="true" />
		</beans:bean>
		<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
		</beans:bean>
		<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
			<beans:constructor-arg ref="sessionRegistry"/>
		</beans:bean>
		</beans:list>
	</beans:constructor-arg>
</beans:bean>

Explain:

ConcurrentSessionControlAuthenticationStrategy control session, check max session and reject when reach to max sessions, propery maximumSessions to define max session accepted

5. Coding future deleted or block user

Step 1 to 4 above is simple configuration, this step is your logic

In code sample bellow, i delete an user, user will be logout emergency

@RequestMapping(value = { "/user/delete" }, method = RequestMethod.POST)
public @ResponseBody String deleteUserController(HttpServletRequest request, Model model,
		@RequestParam("username") String username) {
	try {
		List<Object> users = sessionRegistry.getAllPrincipals();
		for (Object user: users) {
			List<SessionInformation> sessions = sessionRegistry.getAllSessions(user, false);
			for(SessionInformation session : sessions) {
				org.springframework.security.core.userdetails.User userSession = (org.springframework.security.core.userdetails.User) session.getPrincipal();
				if(userSession.getUsername().equals(username)) {
					session.expireNow();
				}
			}
		}
		this.userService.deleteUserByUserName(username);
		return "1";
	} catch (Exception ex) {
		logger.error(ex.getMessage(), ex);
		return "-1";
	}
}

Explain :

sessionRegistry.getAllPrincipals() is method to get all sessions logined in to your webapp

I fetch on all sessions and get username of each session, compare with username, that have been deleted, and call mwthod expireNow() to force logout session

Good luck!