java - 避免 @Secured 注解的重复值
问题描述
我正在尝试使用@Secured
以下方法保护我的服务方法:
public interface IUserService {
@Secured({"ROLE_ROLE1", "ROLE_ROLE2"})
ResponseEntity saveUser(CreateUserDtoRequest userDto);
}
我想知道有没有办法{"ROLE_ROLE1", "ROLE_ROLE2"}
在变量中定义并value
从properties
文件中读取它?如果你能建议我一个技巧,那就太好了:
{"ROLE_ROLE1", "ROLE_ROLE2"}
删除其他方法中的重复- 如果将来访问方法所需的角色发生变化,则无需更改代码、重新编译和再次部署。
解决方案
有几种方法可以满足您的需要:
开发您的自定义MethodSecurityExpressionOperations
在本教程中,您将看到如何处理一种新的自定义安全方法(第 5 节)或覆盖当前的安全方法hasAuthority
(第 6 节)。
开发您的自定义方法以用于SpEL
可能是一个更简单的选择,步骤可能是以下步骤:
1.application.yml
在您的(或properties
)中包含允许的角色
security:
rolesAllowed: ADMIN,USER
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();
}
}
3.添加安全检查:
@PreAuthorize("@fromPropertyRoleSecurityCheck.verifyRoles()")
public ResponseEntity<MyDto> findById(@PathVariable @Positive Integer id) {
...
}
如果您不想在每次这些角色更改时重新编译/部署项目,您可以将它们保存在例如数据库之类的外部存储中(更新任何提供的示例以处理这种情况应该不是问题)。在第二个中,我使用了一个属性来保持简单,但是很容易包含一个从数据库Repository
中FromPropertyRoleSecurityCheck
获取它们的属性。
PD。提供的链接和自定义链接的示例是在控制器层中开发的,但它们也应该在服务层中工作。
推荐阅读
- c# - 获取 xml 节点属性并将它们分配给控件
- c++ - 将 char 转换为 std::string,然后连接
- nginx - 用于 Kubernetes 部署的 ASP.NET Core 的粘性会话
- windows - 使用批处理命令通过 FTP 发送到大型机后如何将本地文件移动到另一个本地文件夹
- java - Java Android LiveData 调用 Room 查询依赖于其他 LiveData
- c# - C# => Arduino 连接崩溃
- reactjs - 如何从搜索表单中的多个 id 获取值以用于 axios 调用
- react-native - 如何使用 MapBox 和 React Native 将地图置于点击符号的中心?
- javascript - Nodemailer - MS Exchaneg 服务器 - 无法验证第一个证书时出错
- javascript - 如何自动将`.js`添加到模块地址自动修复?