Dynamically update user permissions in spring security

     During the execution of the program, sometimes there is such a demand that the permissions of some roles or the permissions corresponding to some people need to be dynamically updated. When the current online user has this role or has this permission, they do not log out of the system. , the permissions he has that need to be dynamically changed.

 

Requirement: Zhang San has the authority of ROLE_ADMIN and ROLE_USER after logging in to the system, but the authority of ROLE_ADMIN is too strong and should not be given to Zhang San. The background administrator should be able to cancel the authority of Zhang San's ROLE_ADMIN, then Zhang San is still online and has no authority. If you log out of the system, you should no longer be able to access resources with ROLE_ADMIN permissions.

 

Solutions:

    1. To monitor all online users in the system, you need to monitor session creation and destruction events

    2. After successful login, spring secuirty will change the value of sessionId in order to prevent session curing attacks. Therefore, it is necessary to monitor the SessionFixationProtectionEvent event released by spring security.

    3. When the resources in our system change, we need to publish a resource change event of our own, and modify the permissions of the current online user in this event.

 

The general steps are as follows:

1. Get all online user objects in the system

    |- Register HttpSessionEventPublisher as a listener, after registration, you can listen to session creation and destruction events

/**
	 * Register Servlet Listener to publish Session creation and destruction events
	 */
	@Bean
	public ServletListenerRegistrationBean httpSessionEventPublisher() {
		ServletListenerRegistrationBean<HttpSessionEventPublisher> registration = new ServletListenerRegistrationBean<>();
		registration.setListener(new HttpSessionEventPublisher());
		return registration;
	}

    |- Listen to the session creation event ( HttpSessionCreatedEvent ), in this step you need to save the session object

/**
 * Monitor session creation object
 */
@Component
@ Slf4j
class HttpSessionCreatedEventListener implements ApplicationListener<HttpSessionCreatedEvent> {

	@Override
	public void onApplicationEvent(HttpSessionCreatedEvent event) {
		log.info("新建session:{}", event.getSession().getId());
		try {
			// save session
		} catch (Exception e) {
			log.info(String.format("Add session: [%s] has an exception.", event.getSession().getId()), e);
		}
	}
}

   |- Listen to the destruction event of the session ( HttpSessionDestroyedEvent ), this event is mainly to remove the session object that does not exist

 

/**
 * Listen for session invalidation events
 */
@Component
@ Slf4j
class SessionDestroyedEventListener implements ApplicationListener<HttpSessionDestroyedEvent> {

	@Override
	public void onApplicationEvent(HttpSessionDestroyedEvent event) {
		log.info("失效session:{}", event.getSession().getId());
		try {
			// remove session
		} catch (Exception e) {
			log.error(String.format("Invalid session: [%s] exception occurred.", event.getId()), e);
		}
	}
}

   |- Save all session objects in the system

 

Second, monitor the SessionFixationProtectionEvent event . This is mainly for spring security to prevent session curing attacks. After the user logs in successfully, it will modify the value of the user's sessionId and publish this event. You need to monitor it here, otherwise the session in the session saved in the previous step will be modified. The value of sessionId is problematic.

 ( Note: You can view org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#sessionStrategy this )

 

/**
 * @author huan.fu
 * After Spring security successfully logs in, to prevent session curing attacks, the old sessionId will be destroyed and a new sessionId will be regenerated.
 * So you need to do something here
 */
@Component
class SessionFixationProtectionEventListener implements ApplicationListener<SessionFixationProtectionEvent> {
	@Override
	public void onApplicationEvent(SessionFixationProtectionEvent event) {
		String oldSessionId = event.getOldSessionId();
		String newSessionId = event.getNewSessionId();
                // Change the value of sessionId
	}
}

 

3. When the resources in the system change, modify the resources of the current online user

    With the foundation of the above two steps, we can get all the current online user objects. When the resources in our own system change, for example, adding a new role to the user, deleting a role of the user, or giving When a role is newly added or deleted, we can do some processing on the current user ( such as filtering users who do not have this permission, processing when the session is still newly created, etc. ) to dynamically update the user's permissions.

 

  Get current user information:

  1. Get from session:

SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
					Object principal =  securityContext.getAuthentication().getPrincipal();

  2. Reload the resources of the current user

 

/**
 * Reload user's permissions
 *
 * @param session
 */
private void reloadUserAuthority(HttpSession session) {

	// new permissions
	List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(new String[]{"Query from the database"});

	SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
	Authentication authentication = securityContext.getAuthentication();
	SecurityUser principal = (SecurityUser) authentication.getPrincipal();
	principal.setAuthorities(authorityList);

	// Renew a new token, because the permissions in Authentication are immutable.
	UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
			principal, authentication.getCredentials(),
			authorityList);
	result.setDetails(authentication.getDetails());
	securityContext.setAuthentication(result);
}

 

  At this point, it should be possible to dynamically modify the permission information of online users.

  Note : Some of the above code is incomplete, but the general idea is this.

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326225407&siteId=291194637