Как проверить "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
класса.
на 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 определяется как bean в spring-security.XML.
мой подход с помощью Java8, проходя кома разделенных ролей даст вам true или false
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`
}