mvc - spring java tutorial
Cómo comprobar "hasRole" en Java Code con Spring Security? (14)
¡La respuesta de @gouki es la mejor!
Solo un consejo de cómo la primavera realmente hace esto.
Hay una clase llamada SecurityContextHolderAwareRequestWrapper
que implementa la clase ServletRequestWrapper
.
SecurityContextHolderAwareRequestWrapper
anula el isUserInRole
y busca Authentication
usuario (que es administrado por Spring) para encontrar si el usuario tiene un rol o no.
SecurityContextHolderAwareRequestWrapper
el código es como sigue:
@Override
public boolean isUserInRole(String role) {
return isGranted(role);
}
private boolean isGranted(String role) {
Authentication auth = getAuthentication();
if( rolePrefix != null ) {
role = rolePrefix + role;
}
if ((auth == null) || (auth.getPrincipal() == null)) {
return false;
}
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
if (authorities == null) {
return false;
}
//This is the loop which do actual search
for (GrantedAuthority grantedAuthority : authorities) {
if (role.equals(grantedAuthority.getAuthority())) {
return true;
}
}
return false;
}
¿Cómo verificar la autorización o el permiso del usuario en Java Code? Por ejemplo, quiero mostrar u ocultar el botón para el usuario dependiendo de la función. Hay anotaciones como:
@PreAuthorize("hasRole(''ROLE_USER'')")
¿Cómo hacerlo en código Java? Algo como :
if(somethingHere.hasRole("ROLE_MANAGER")) {
layout.addComponent(new Button("Edit users"));
}
A la mayoría de las respuestas les faltan algunos puntos:
Papel y autoridad no son lo mismo en primavera. Mira aquí para more detalles.
Los nombres de roles son iguales a
rolePrefix
+authority
.El prefijo de rol predeterminado es
ROLE_
, sin embargo, es configurable. Mira here .
Por lo tanto, una verificación de función adecuada debe respetar el prefijo de función si está configurado.
Desafortunadamente, la personalización del prefijo de roles en Spring es un poco hacky, en muchos lugares el prefijo predeterminado, ROLE_
está codificado, pero además de eso, se comprueba un bean de tipo GrantedAuthorityDefaults
en el contexto Spring, y si existe, el rol personalizado el prefijo que tiene es respetado.
Reuniendo toda esta información, una mejor implementación del verificador de roles sería algo así como:
@Component
public class RoleChecker {
@Autowired(required = false)
private GrantedAuthorityDefaults grantedAuthorityDefaults;
public boolean hasRole(String role) {
String rolePrefix = grantedAuthorityDefaults != null ? grantedAuthorityDefaults.getRolePrefix() : "ROLE_";
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.map(Authentication::getAuthorities)
.map(Collection::stream)
.orElse(Stream.empty())
.map(GrantedAuthority::getAuthority)
.map(authority -> rolePrefix + authority)
.anyMatch(role::equals);
}
}
En lugar de usar un bucle para encontrar la autoridad de UserDetails, puede hacer:
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
En nuestro proyecto, estamos usando una jerarquía de roles, mientras que la mayoría de las respuestas anteriores solo apuntan a verificar un rol específico, es decir, solo verificaría el rol dado, pero no para ese rol ni para la jerarquía.
Una solución para esto:
@Component
public class SpringRoleEvaluator {
@Resource(name="roleHierarchy")
private RoleHierarchy roleHierarchy;
public boolean hasRole(String role) {
UserDetails dt = AuthenticationUtils.getSessionUserDetails();
for (GrantedAuthority auth: roleHierarchy.getReachableGrantedAuthorities(dt.getAuthorities())) {
if (auth.toString().equals("ROLE_"+role)) {
return true;
}
}
return false;
}
RoleHierarchy se define como un bean en spring-security.xml.
Esto es como llegar a la pregunta desde el otro lado, pero pensé en tirarlo ya que realmente tuve que cavar en internet para descubrirlo.
Hay muchas cosas sobre cómo verificar roles, pero no mucho sobre lo que realmente está comprobando cuando dice hasRole ("blah")
HasRole comprueba las autoridades otorgadas para el principal autenticado actualmente
Entonces, realmente, cuando ves hasRole ("blah") realmente significa hasAuthority ("blah") .
En el caso que he visto, haces esto con una clase que Implementa UserDetails que define un método llamado getAuthorities. En esto, básicamente agregará una new SimpleGrantedAuthority("some name")
a una lista basada en cierta lógica. Los nombres en esta lista son los elementos marcados por las instrucciones hasRole.
Supongo que en este contexto, el objeto UserDetails es el principal autenticado actualmente. Hay algo mágico que sucede dentro y alrededor de los proveedores de autenticación y más específicamente del administrador de autenticación que hace que esto suceda.
Estoy usando esto:
@RequestMapping(method = RequestMethod.GET)
public void welcome(SecurityContextHolderAwareRequestWrapper request) {
boolean b = request.isUserInRole("ROLE_ADMIN");
System.out.println("ROLE_ADMIN=" + b);
boolean c = request.isUserInRole("ROLE_USER");
System.out.println("ROLE_USER=" + c);
}
La respuesta de JoseK no se puede usar cuando estás en la capa de servicio, donde no quieres introducir un acoplamiento con la capa web de la referencia a la solicitud HTTP. Si está buscando resolver los roles mientras está en la capa de servicio, la respuesta de Gopi es el camino a seguir.
Sin embargo, es un poco largo aliento. Se puede acceder a las autoridades directamente desde la Autenticación. Por lo tanto, si puede suponer que tiene un usuario conectado, lo siguiente lo hace:
/**
* @return true if the user has one of the specified roles.
*/
protected boolean hasRole(String[] roles) {
boolean result = false;
for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
String userRole = authority.getAuthority();
for (String role : roles) {
if (role.equals(userRole)) {
result = true;
break;
}
}
if (result) {
break;
}
}
return result;
}
Mejor tarde, nunca, déjame poner mi valor de 2 centavos.
En el mundo de JSF, dentro de mi bean administrado, hice lo siguiente:
HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");
Como mencioné anteriormente, mi entendimiento es que se puede hacer de la manera sin aliento como sigue:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
userDetails = (UserDetails) principal;
Collection authorities = userDetails.getAuthorities();
}
Por extraño que parezca, no creo que haya una solución estándar para este problema, ya que el control de acceso de seguridad de primavera se basa en expresiones , no en Java. es posible que compruebe el código fuente de DefaultMethodSecurityExpressionHandler para ver si puede volver a utilizar algo que están haciendo allí
Puede implementar un método hasRole () como a continuación - (Esto se prueba en spring security 3.0.x no estoy seguro acerca de otras versiones).
protected final boolean hasRole(String role) {
boolean hasRole = false;
UserDetails userDetails = getUserDetails();
if (userDetails != null) {
Collection<GrantedAuthority> authorities = userDetails.getAuthorities();
if (isRolePresent(authorities, role)) {
hasRole = true;
}
}
return hasRole;
}
/**
* Get info about currently logged in user
* @return UserDetails if found in the context, null otherwise
*/
protected UserDetails getUserDetails() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
userDetails = (UserDetails) principal;
}
return userDetails;
}
/**
* Check if a role is present in the authorities of current user
* @param authorities all authorities assigned to current user
* @param role required authority
* @return true if role is present in list of authorities assigned to current user, false otherwise
*/
private boolean isRolePresent(Collection<GrantedAuthority> authorities, String role) {
boolean isRolePresent = false;
for (GrantedAuthority grantedAuthority : authorities) {
isRolePresent = grantedAuthority.getAuthority().equals(role);
if (isRolePresent) break;
}
return isRolePresent;
}
Puede obtener ayuda de la clase AuthorityUtils . Comprobando el rol como una sola línea:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
/* ... */
}
Advertencia: Esto no verifica la jerarquía de roles, si es que existe.
Puede recuperar el contexto de seguridad y luego usar eso:
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
protected boolean hasRole(String role) {
// get security context from thread local
SecurityContext context = SecurityContextHolder.getContext();
if (context == null)
return false;
Authentication authentication = context.getAuthentication();
if (authentication == null)
return false;
for (GrantedAuthority auth : authentication.getAuthorities()) {
if (role.equals(auth.getAuthority()))
return true;
}
return false;
}
Spring Security 3.0 tiene esta API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
puede usar el método isUserInRole del objeto HttpServletRequest.
algo como:
public String createForm(HttpSession session, HttpServletRequest request, ModelMap modelMap) {
if (request.isUserInRole("ROLE_ADMIN")) {
// code here
}
}