Java 避免@Secured注释的重复值
我正在尝试使用Java 避免@Secured注释的重复值,java,spring-boot,spring-security,Java,Spring Boot,Spring Security,我正在尝试使用@Secured保护我的服务方法,如下所示: public interface IUserService { @Secured({"ROLE_ROLE1", "ROLE_ROLE2"}) ResponseEntity saveUser(CreateUserDtoRequest userDto); } 我想知道是否有一种方法可以在变量中定义{“ROLE\u ROLE1”,“ROLE\u ROLE2”},并从属性文件中读取其值? 如
@Secured
保护我的服务方法,如下所示:
public interface IUserService {
@Secured({"ROLE_ROLE1", "ROLE_ROLE2"})
ResponseEntity saveUser(CreateUserDtoRequest userDto);
}
我想知道是否有一种方法可以在变量中定义{“ROLE\u ROLE1”,“ROLE\u ROLE2”}
,并从属性文件中读取其值
?
如果你能给我建议一个窍门,那就太好了:
在其他方法中删除重复的{“ROLE\u ROLE1”、“ROLE\u ROLE2”}
如果将来访问方法所需的角色发生更改,则无需更改代码、重新编译并再次部署
有几种方法可以满足您的需要:
开发自定义的MethodSecurityExpressionOperations
在本文中,您将看到如何处理新的自定义安全方法(第5节)或覆盖当前的hasAuthority
one(第6节)
开发自定义方法以在SpEL
可能是esier选项,步骤可以是以下步骤:
1.在应用程序.yml
中包含允许的角色(或属性
)
2.定义类以检查这些角色和授权用户角色。例如:
import org.springframework.beans.factory.annotation.Value;
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;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toSet;
@Component
public class FromPropertyRoleSecurityCheck {
private final static String ROLE_SEPARATOR = ",";
@Value("${security.rolesAllowed}")
private String rawRolesAllowed;
public boolean verifyRoles() {
return getPrincipalAuthorities()
.map(auth -> {
Set<String> rolesAllowed = Stream.of(rawRolesAllowed.split(ROLE_SEPARATOR))
.map(String::trim)
.collect(toSet());
return verifyAllowedRoles(rolesAllowed, auth);
})
.orElse(false);
}
private Optional<Collection<? extends GrantedAuthority>> getPrincipalAuthorities() {
return ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getAuthorities);
}
private boolean verifyAllowedRoles(final Collection<String> rolesAllowed,
final Collection<? extends GrantedAuthority> principalAuthorities) {
if (CollectionUtils.isEmpty(rolesAllowed)) {
return true;
}
if (CollectionUtils.isEmpty(principalAuthorities)) {
return false;
}
Set<String> rolesDiff = principalAuthorities.stream().map(GrantedAuthority::getAuthority).collect(toSet());
rolesDiff.removeAll(rolesAllowed);
return rolesDiff.size() != principalAuthorities.size();
}
}
import org.springframework.beans.factory.annotation.Value;
导入org.springframework.security.core.Authentication;
导入org.springframework.security.core.GrantedAuthority;
导入org.springframework.security.core.context.SecurityContext;
导入org.springframework.security.core.context.SecurityContextHolder;
导入org.springframework.stereotype.Component;
导入org.springframework.util.CollectionUtils;
导入java.util.Collection;
导入java.util.Optional;
导入java.util.Set;
导入java.util.stream.stream;
导入静态java.util.Optional.ofNullable;
导入静态java.util.stream.Collectors.toSet;
@组成部分
来自PropertyRoleSecurityCheck的公共类{
私有最终静态字符串角色_SEPARATOR=“,”;
@值(${security.rolesAllowed}”)
允许私人字符串原始角色;
公共布尔验证角色(){
返回getPrincipalAuthorities()
.map(auth->{
Set rolesAllowed=Stream.of(rawsrolesallowed.split(角色分隔符))
.map(字符串::trim)
.收集(toSet());
返回verifyAllowedRoles(角色允许,身份验证);
})
.orElse(假);
}
私有选项您可以在应用程序中使用@PreAuthorize
,但您可以定义用户权限并将其作为角色添加到用户中。User1->role\u adming->[保存用户,编辑用户]。这与您的方法类似:@PreAuthorize(value=“hasAnyAuthority”(+)T(ua.pmdev.auctionizer.rest.user.domain.UserPermission).ADMIN.name(),“+”T(ua.pmdev.auctionizer.rest.user.domain.UserPermission.ALL.name()))
我没有问题解决@PreAuthorize
的问题,因为在线上已经有了一些解决方案。因为@Secured
注释更适合在我的情况下使用(除了不必使用conditionalEL
之外,由于没有hasRole
的内容,因此更简单,可读性更高),我想知道是否可以动态检查@Secured
中的角色
,谢谢@doctore的回复。您的解决方案看起来很好,我对此表示赞同。此外,我将尝试该解决方案并让您知道结果。该解决方案有效。谢谢。只需一件小事:从那时起就不需要角色分隔符
您可以将rawRolesAllowed
定义为List
,而不是String
,很乐意提供帮助。关于List
,是的,有更简单的方法来使用它:
import org.springframework.beans.factory.annotation.Value;
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;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toSet;
@Component
public class FromPropertyRoleSecurityCheck {
private final static String ROLE_SEPARATOR = ",";
@Value("${security.rolesAllowed}")
private String rawRolesAllowed;
public boolean verifyRoles() {
return getPrincipalAuthorities()
.map(auth -> {
Set<String> rolesAllowed = Stream.of(rawRolesAllowed.split(ROLE_SEPARATOR))
.map(String::trim)
.collect(toSet());
return verifyAllowedRoles(rolesAllowed, auth);
})
.orElse(false);
}
private Optional<Collection<? extends GrantedAuthority>> getPrincipalAuthorities() {
return ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getAuthorities);
}
private boolean verifyAllowedRoles(final Collection<String> rolesAllowed,
final Collection<? extends GrantedAuthority> principalAuthorities) {
if (CollectionUtils.isEmpty(rolesAllowed)) {
return true;
}
if (CollectionUtils.isEmpty(principalAuthorities)) {
return false;
}
Set<String> rolesDiff = principalAuthorities.stream().map(GrantedAuthority::getAuthority).collect(toSet());
rolesDiff.removeAll(rolesAllowed);
return rolesDiff.size() != principalAuthorities.size();
}
}
@PreAuthorize("@fromPropertyRoleSecurityCheck.verifyRoles()")
public ResponseEntity<MyDto> findById(@PathVariable @Positive Integer id) {
...
}