Springboot Security tiene el rol que no funciona
No puedo usar hasRole
el método en @PreAuthorize
la anotación. También request.isUserInRole(“ADMIN”)
da false
. ¿Qué me estoy perdiendo? Aunque .hasAuthority(“ADMIN”)
funciona bien.
Estoy asignando autoridades a los usuarios desde una base de datos.
Debe nombrar su autoridad con el prefijo ROLE_
a usar isUserInRole
; consulte la Referencia de seguridad de Spring :
HttpServletRequest.isUserInRole(String) determinará si
SecurityContextHolder.getContext().getAuthentication().getAuthorities()
contiene unGrantedAuthority
con el rol pasadoisUserInRole(String)
. Normalmente, los usuarios no deben pasar el prefijo "ROLE_" a este método, ya que se agrega automáticamente. Por ejemplo, si desea determinar si el usuario actual tiene la autoridad "ROLE_ADMIN", puede utilizar lo siguiente:boolean isAdmin = httpServletRequest.isUserInRole("ADMIN");
Lo mismo para hasRole
(también hasAnyRole
), consulte la referencia de seguridad de Spring :
Devuelve
true
si el principal actual tiene el rol especificado. De forma predeterminada, si el rol proporcionado no comienza con 'ROLE_', se agregará. Esto se puede personalizar modificando el archivodefaultRolePrefix
onDefaultWebSecurityExpressionHandler
.
Consulte también Referencia de seguridad de Spring :
46.3.3 ¿Qué significa "ROLE_" y por qué lo necesito en los nombres de mis roles?
Spring Security tiene una arquitectura basada en votantes, lo que significa que una serie de
AccessDecisionVoters
. Los votantes actúan sobre los "atributos de configuración" que se especifican para un recurso seguro (como la invocación de un método). Con este enfoque, no todos los atributos pueden ser relevantes para todos los votantes y un votante necesita saber cuándo debe ignorar un atributo (abstenerse) y cuándo debe votar para otorgar o denegar el acceso según el valor del atributo. El votante más común es elRoleVoter
que por defecto vota siempre que encuentra un atributo con el prefijo "ROLE_". Hace una comparación simple del atributo (como "ROLE_USER") con los nombres de las autoridades que se le han asignado al usuario actual. Si encuentra una coincidencia (tienen una autoridad llamada "ROLE_USER"), vota para conceder el acceso; de lo contrario, vota para denegar el acceso.
Tuve que improvisar un poco, tal vez haya otras formas más sencillas que la mía, pero en el momento en que trabajé en esto no me quedó más remedio que improvisar un poco, después de una investigación exhaustiva llegué a esta solución. Spring Security tiene una interfaz llamada AccessDecisionManager
, deberá implementarla.
@Component
public class RolesAccessDecisionManager implements AccessDecisionManager {
private final static String AUTHENTICATED = "authenticated";
private final static String PERMIT_ALL = "permitAll";
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
collection.forEach(configAttribute -> {
if (!this.supports(configAttribute))
throw new AccessDeniedException("ACCESS DENIED");
});
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
String rolesAsString = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));
if (configAttribute.toString().contains(rolesAsString))
return true;
else
return (configAttribute.toString().contains(PERMIT_ALL) || configAttribute.toString().contains(AUTHENTICATED));
}
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
Ahora, para admitir este administrador de decisiones de acceso personalizado con su configuración de seguridad, haga esto en la configuración de seguridad:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
// other configs
.accessDecisionManager(this.accessDecisionManager)
accessDecisionManager
es el bean autowired de la AccessDecisionManager
implementación que has creado.