with tutorial j_spring_security_check example español ejemplo java spring spring-security

java - j_spring_security_check - spring security tutorial



Cómo recargar las autoridades en la actualización del usuario con Spring Security (4)

Estoy haciendo una aplicación con autenticación por OpenID usando Spring Security. Cuando el usuario ha iniciado sesión, algunas autoridades se cargan en su sesión.

Tengo un usuario con pleno derecho que puede modificar las autorizaciones (revocar, agregar roles) de otros usuarios. Mi pregunta es, ¿cómo cambiar las autoridades de sesión de usuario dinámicamente? (No puedo usar SecurityContextHolder porque quiero cambiar otra sesión de usuario).

Forma simple: invalidar sesión de usuario, pero ¿cómo? Mejor manera: actualizar sesión de usuario con nuevas autoridades, pero ¿cómo?


El punto clave: debe poder acceder a los usuarios de SecurityContext s.

Si está en el entorno de servlet y está utilizando HttpSession como securityContextRepository en su securityContextPersistenceFilter , entonces puede hacerse con SessionRegistry de primavera. Para obligar al usuario a volver a realizar la autenticación (debería ser mejor que la revocación de permisos silenciosos) invalide su HttpSession . No olvide agregar HttpSessionEventPublisher a web.xml

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

Si está usando thread-local securityContextRepository , entonces debe agregar un filtro personalizado a springSecurityFilterChain para administrar el registro de SecurityContext . Para hacer esto, debe usar la configuración springSecurityFilterChain (sin acceso directo de espacio de nombres). Con la configuración de beans simples con filtros personalizados, tendrá un control total sobre la autenticación y la autorización.

Algunos enlaces no resuelven exactamente su problema (no OpenID), pero pueden ser útiles:


Gracias, ayúdame mucho! Con SessionRegistry , puedo usar getAllPrincipals() para comparar al usuario para modificarlo con los usuarios activos actuales en las sesiones. Si existe una sesión, puedo invalidar su sesión usando: expireNow() (de SessionInformation ) para forzar la re-autenticación.

¿Pero no entiendo la utilidad de securityContextPersistenceFilter ?

EDITAR:

// user object = User currently updated // invalidate user session List<Object> loggedUsers = sessionRegistry.getAllPrincipals(); for (Object principal : loggedUsers) { if(principal instanceof User) { final User loggedUser = (User) principal; if(user.getUsername().equals(loggedUser.getUsername())) { List<SessionInformation> sessionsInfo = sessionRegistry.getAllSessions(principal, false); if(null != sessionsInfo && sessionsInfo.size() > 0) { for (SessionInformation sessionInformation : sessionsInfo) { LOGGER.info("Exprire now :" + sessionInformation.getSessionId()); sessionInformation.expireNow(); sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); // User is not forced to re-logging } } } } }


Si alguien sigue investigando cómo actualizar las autorizaciones de otro usuario sin obligar a ese usuario a volver a autenticarse, puede intentar agregar un interceptor que vuelva a cargar la autenticación. Esto asegurará que sus autoridades estén siempre actualizadas.

Sin embargo, debido al interceptor adicional, habrá algunos impactos en el rendimiento (por ejemplo, si obtiene sus roles de usuario de su base de datos, se consultará para cada solicitud HTTP).

@Component public class VerifyAccessInterceptor implements HandlerInterceptor { // ... @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Set<GrantedAuthority> authorities = new HashSet<>(); if (auth.isAuthenticated()) { authorities.add(new SimpleGrantedAuthority("ROLE_USER")); } User userFromDatabase = getUserFromDatabase(auth.getName()); if (userFromDatabase != null) { // add whatever authorities you want here authorities.add(new SimpleGrantedAuthority("...")); } Authentication newAuth = null; if (auth.getClass() == OAuth2AuthenticationToken.class) { OAuth2User principal = ((OAuth2AuthenticationToken)auth).getPrincipal(); if (principal != null) { newAuth = new OAuth2AuthenticationToken(principal, authorities,(((OAuth2AuthenticationToken)auth).getAuthorizedClientRegistrationId())); } } SecurityContextHolder.getContext().setAuthentication(newAuth); return true; } }

Esta implementación específica utiliza OAuth2 ( OAuth2AuthenticationToken ), pero puede usar UsernamePasswordAuthenticationToken lugar.

Y ahora, para agregar su interceptor a la configuración:

@Configuration public class WebConfiguration extends WebMvcConfigurationSupport { @Autowired private VerifyAccessInterceptor verifyAccessInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(verifyAccessInterceptor).addPathPatterns("/**"); } }

También hice un artículo sobre esto .


Si necesita actualizar dinámicamente las autorizaciones de un usuario conectado (cuando estas han cambiado, por cualquier motivo), sin tener que cerrar sesión e iniciar sesión, solo tiene que restablecer el objeto de Authentication (token de seguridad) en Spring SecurityContextHolder .

Ejemplo:

Authentication auth = SecurityContextHolder.getContext().getAuthentication(); List<GrantedAuthority> updatedAuthorities = new ArrayList<>(auth.getAuthorities()); updatedAuthorities.add(...); //add your role here [e.g., new SimpleGrantedAuthority("ROLE_NEW_ROLE")] Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities); SecurityContextHolder.getContext().setAuthentication(newAuth);