Как проверить "hasRole" в Java-коде с Spring Security?
Как проверить права пользователя или разрешения в коде Java ? Например - я хочу показать или скрыть кнопку для пользователя в зависимости от роли. Есть аннотации, такие как:
@PreAuthorize("hasRole('ROLE_USER')")
Как сделать это в коде Java? Что-то вроде :
if(somethingHere.hasRole("ROLE_MANAGER")) {
layout.addComponent(new Button("Edit users"));
}
16 ответов:
Spring Security 3.0 имеет этот API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
можно использовать метод isUserInRole объекта HttpServletRequest.
что-то типа:
public String createForm(HttpSession session, HttpServletRequest request, ModelMap modelMap) { if (request.isUserInRole("ROLE_ADMIN")) { // code here } }
вместо того, чтобы использовать цикл, чтобы найти полномочия от UserDetails вы можете сделать:
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
вы можете получить контекст безопасности, а затем использовать это:
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; }
вы можете реализовать метод hasRole (), как показано ниже - (это проверено на spring security 3.0.x не уверен в других версиях.)
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; }
Я использую этот:
@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); }
ответ от JoseK не может быть использован, когда вы находитесь в своем сервисном слое, где вы не хотите вводить связь с веб-слоем из ссылки на HTTP-запрос. Если вы ищете решение ролей в то время как на уровне сервиса, ответ Gopi-это путь.
однако, это немного долго наматывается. Доступ к властям можно получить прямо из аутентификации. Следовательно, если вы можете предположить, что пользователь вошел в систему, это делает следующее:
/** * @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; }
Как ни странно, я не думаю, что есть стандартное решение этой проблемы, так как контроль доступа spring-security выражение на основе, не на основе java. вы можете проверить исходный код DefaultMethodSecurityExpressionHandler чтобы увидеть, если вы можете повторно использовать то, что они там делают
лучше поздно, чем никогда, позвольте мне положить в мои 2 цента стоит.
в мире JSF, в моем управляемом Бобе, я сделал следующее:
HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");Как уже упоминалось выше, я понимаю, что это может быть сделано длинный извилистый путь следующим образом:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserDetails userDetails = null; if (principal instanceof UserDetails) { userDetails = (UserDetails) principal; Collection authorities = userDetails.getAuthorities(); }
Это вроде как приходит на вопрос с другого конца, но я думал, что брошу его, так как мне действительно нужно было копать в интернете, чтобы узнать это.
есть много вещей о том, как проверить роли, но не так много говорят, что вы на самом деле проверяете, когда вы говорите hasRole("бла")
HasRole проверяет предоставленные полномочия для текущего аутентифицированного участника
поэтому, когда вы видите hasRole("бла") действительно означает hasAuthority("бла").
в случае, когда я видел, вы делаете это с классом, который реализует UserDetails, который определяет метод, называемый getAuthorities. В этом вы в принципе добавить
new SimpleGrantedAuthority("some name")к списку, основанному на некоторой логике. Имена в этом списке-это вещи, проверенные инструкциями hasRole.Я предполагаю, что в этом контексте объект UserDetails является в настоящее время аутентифицированным участником. Есть какая-то магия, которая происходит внутри и вокруг поставщиков аутентификации и более конкретно менеджер аутентификации, который делает это возможным.
ответ @gouki лучше всего!
просто подсказка о том, как весна действительно это делает.
есть класс с именем
SecurityContextHolderAwareRequestWrapper, который реализуетServletRequestWrapperкласса.The
SecurityContextHolderAwareRequestWrapperпереопределяетisUserInRoleпоиск (который управляется Spring), чтобы найти, если пользователь имеет роль или нет.
SecurityContextHolderAwareRequestWrapperкод, например:@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; }
вы можете получить некоторую помощь от AuthorityUtils класса. Проверка роли в качестве однострочного:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) { /* ... */ }предостережение: это не проверяет иерархию ролей, если таковая существует.
в большинстве ответов отсутствуют некоторые моменты:
роль и власть-это не одно и то же весной. Смотрите здесь для больше подробности.
имена ролей равны
rolePrefix+authority.префикс роли по умолчанию -
ROLE_, однако, это настраивается. Смотрите здесь.поэтому правильная проверка роли должна учитывать префикс роли, если он есть сконфигурированный.
к сожалению, настройка префикса роли весной немного хаки, во многих местах префикс по умолчанию,
ROLE_жестко, но в дополнение к этому, в зернах типаGrantedAuthorityDefaultsпроверяется в контексте Spring, и если он существует, пользовательский префикс роли, который он имеет, соблюдается.объединяя всю эту информацию, лучшая реализация проверки ролей будет выглядеть примерно так:
@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); } }
в нашем проекте мы используем иерархию ролей, в то время как большинство из приведенных выше ответов направлены только на проверку конкретной роли, т. е. будут проверять только для данной роли, но не для этой роли и вверх по иерархии.
решение для этого:
@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 определяется как Боб в spring-security.XML.
мой подход с помощью Java8, проходя кома разделенных ролей даст вам истину или ложь
public static Boolean hasAnyPermission(String permissions){ Boolean result = false; if(permissions != null && !permissions.isEmpty()){ String[] rolesArray = permissions.split(","); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); for (String role : rolesArray) { boolean hasUserRole = authentication.getAuthorities().stream().anyMatch(r -> r.getAuthority().equals(role)); if (hasUserRole) { result = true; break; } } } return result; }
чтобы проверить роль пользователя, вы можете попробовать это:
public static boolean isCurrentUserInRole(String authority) { SecurityContext securityContext = SecurityContextHolder.getContext(); Authentication authentication = securityContext.getAuthentication(); if (authentication != null) { return authentication.getAuthorities().stream() .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority)); } return false; }и затем :
if(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.ADMIN)) { `enter code here` }
Comments