Ответ 1
Spring Security 3.0 имеет этот API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
Вам придется ввести оболочку, прежде чем использовать ее.
Как проверить полномочия пользователя или разрешение в Java-коде? Например - я хочу показать или скрыть кнопку для пользователя в зависимости от роли. Есть такие аннотации, как:
@PreAuthorize("hasRole('ROLE_USER')")
Как сделать это в Java-коде? Что-то вроде:
if(somethingHere.hasRole("ROLE_MANAGER")) {
layout.addComponent(new Button("Edit users"));
}
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);
}
Вы можете получить помощь от класса AuthorityUtils. Проверка роли в одной строке:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
/* ... */
}
Предупреждение: это не проверяет иерархию ролей, если таковая существует.
Ответ от 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. Подробнее см. Здесь подробнее.
Имена ролей равны rolePrefix
+ authority
.
Префикс роли по умолчанию ROLE_
, однако он настраивается. См. здесь.
Поэтому правильная проверка роли должна учитывать префикс роли, если она настроена.
К сожалению, настройка префикса роли в Spring немного взломана, во многих местах префикс по умолчанию, ROLE_
жестко закодирован, но в дополнение к этому, bean типа 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);
}
}
Как ни странно, я не думаю, что существует стандартное решение этой проблемы, так как управление доступом spring -security - выражение на основе, а не java-based. вы можете проверить исходный код для DefaultMethodSecurityExpressionHandler, чтобы увидеть, можете ли вы повторно использовать то, что они там делают
Лучше поздно, а потом никогда, позвольте мне поставить свои 2 цента.
В мире JSF в моем управляемом bean я сделал следующее:
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();
}
Ответ @gouki - лучший!
Просто подсказка о том, как spring действительно это делает.
Существует класс с именем SecurityContextHolderAwareRequestWrapper
, который реализует класс ServletRequestWrapper
.
SecurityContextHolderAwareRequestWrapper
переопределяет isUserInRole
и пользователь поиска Authentication
(который управляется 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;
}
Эти две аннотации ниже равны, "hasRole" автоматически добавит префикс "ROLE_". Убедитесь, что у вас есть правильная аннотация. Эта роль установлена в UserDetailsService # loadUserByUsername.
@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")
затем вы можете получить роль в коде Java.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
System.out.println("user role2");
}
Это похоже на вопрос с другого конца, но я думал, что брошу его, потому что мне действительно нужно копаться в Интернете, чтобы узнать это.
Есть много вещей о том, как проверять роли, но не так много говорит, что вы на самом деле проверяете, когда говорите hasRole ( "бла" )
HasRole проверяет предоставленные полномочия для текущего аутентифицированного принципала
Итак, когда вы видите hasRole ( "бла" ), это означает hasAuthority ( "бла" ).
В случае, которое я видел, вы делаете это с помощью класса, который реализует UserDetails, который определяет метод, называемый getAuthorities. В этом вы в основном добавите немного new SimpleGrantedAuthority("some name")
в список, основанный на некоторой логике. Имена в этом списке - это вещи, проверенные операторами hasRole.
Я предполагаю, что в этом контексте объект UserDetails является аутентифицированным в настоящее время принципом. Там есть какая-то магия, которая случается в провайдерах аутентификации и вокруг них, а точнее, менеджер аутентификации, который делает это.
В нашем проекте мы используем иерархию ролей, в то время как большинство из вышеперечисленных ответов предназначены только для проверки конкретной роли, т.е. будет проверять только указанную роль, но не для этой роли и иерархии.
Решение для этого:
@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, Передача разделенных комой ролей даст вам истинное или ложное
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;
}
В вашей пользовательской модели просто добавьте метод hasRole, как показано ниже
public boolean hasRole(String auth) {
for (Role role : roles) {
if (role.getName().equals(auth)) { return true; }
}
return false;
}
Я обычно использую его, чтобы проверить, имеет ли аутентифицированный пользователь роль администратора следующим образом
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // This gets the authentication
User authUser = (User) authentication.getPrincipal(); // This gets the logged in user
authUser.hasRole("ROLE_ADMIN") // This returns true or false