我创建了一个包含一些基本crud方法的CrudController。这很好用。当我想保护这个控制器时,我可以重写超类中的方法,这很好。然而,我不想仅仅为了安全而重写每个方法。为此,我想在类上使用@Secured或@PreAuthorize。
我使用的是Spring Boot 2.2.2(最新版本)。
示例Crud基类
public class CrudController<T, ID> {
@GetMapping
public ResponseEntity<List<T>> findAll() {
// code for returning the list
}
}
实现类
@RestController
@RequestMapping("/helloworld")
@Secured("ROLE_world.view")
public class HelloWorld extends CrudController<World, Long> {
@GetMapping("test")
public ResponseEntity test() {
// This method is secured by the annotation on the class
}
// the findAll from the super class is not secured
}
预期行为
当一个类被注释为@PreAuthorize或@安全时,我希望所有公共方法都是安全的。因此,扩展类中的所有公共方法也应该受到保护。在我的示例中,findAll是不安全的,这是一个很高的安全风险。
尝试
我已经尝试为配置设置以下注释:
在类本身上:
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
在configuration类上:
@Configuration
@EnableAspectJAutoProxy
@EnableWebSecurity
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true,
mode = AdviceMode.PROXY,
proxyTargetClass = true
)
在应用程序中。属性:
spring.aop.proxy-target-class=true
spring.aop.auto=true
作为解决方案,我创建了一个扩展HandlerInterceptorAdapter的类。这只适用于受保护的,因为这样更容易检查角色。
@Component
public class SecuredInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOGGER = getLogger(SecuredInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LOGGER.debug("preHandle {}", handler.getClass());
if (!(handler instanceof HandlerMethod)) {
return super.preHandle(request, response, handler);
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
String[] allowedRoles = getAllowedRoles(handlerMethod);
// No allowed roles, so allow everything
if (allowedRoles.length == 0) {
return super.preHandle(request, response, handler);
}
// Check if we have the needed role
for (String allowedRole : allowedRoles) {
// SecurityUtil checks if an loggedIn keycloak user has the right role
if (SecurityUtil.hasRole(allowedRole)) {
return super.preHandle(request, response, handler);
}
}
// UnauthorizedException is a custom exception which is handle in an @AdviceController
throw new UnauthorizedException("Forbidden");
}
private String[] getAllowedRoles(HandlerMethod method) {
Class<?> targetClass = method.getBean().getClass();
Secured[] annotationsByType = targetClass.getAnnotationsByType(Secured.class);
Secured methodAnnotation = method.getMethodAnnotation(Secured.class);
// Methods are overriding class annotations
if (methodAnnotation != null) {
return methodAnnotation.value();
}
// Get from the class
if (annotationsByType.length > 0) {
return annotationsByType[0].value();
}
// No annotations
return new String[0];
}
}
我在WebConfig中配置此拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securedInterceptor);
}
}
如果你认为我应该接受自己的答案,请投赞成票<欢迎提出意见或其他解决方案。
安全的
注释在类AbstractFallbackMethod odSecurityMetadataSource
中处理,方法如下:
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
// The method may be on an interface, but we need attributes from the target
// class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
if (attr != null) {
return attr;
}
// Second try is the config attribute on the target class.
attr = findAttributes(specificMethod.getDeclaringClass());
if (attr != null) {
return attr;
}
if (specificMethod != method || targetClass == null) {
// Fallback is to look at the original method.
attr = findAttributes(method, method.getDeclaringClass());
if (attr != null) {
return attr;
}
// Last fallback is the class of the original method.
return findAttributes(method.getDeclaringClass());
}
return Collections.emptyList();
}
因此,如果方法没有安全的注释,则在声明类findAttributes(method.getDeclaringClass())中搜索注释,对于您的情况,findAll的声明类是没有任何安全注释的CrudController。
要解决此问题,您应该提供自己的MethodSecurityMetadataSource实现。
下面是一个简单的方法:
>
public class CustomMethodSecurityMetadaSource extends
SecuredAnnotationSecurityMetadataSource {
public CustomMethodSecurityMetadaSource(){
super();
}
@Override
public Collection<ConfigAttribute> getAttributes(Method method,
Class<?> targetClass) {
Collection<ConfigAttribute> attr = super.getAttributes(method, targetClass);
if (CollectionUtils.isEmpty(attr)) {
attr = findAttributes(targetClass);
if (attr != null) return attr;
}
return Collections.emptyList();
}
}
通过扩展GlobalMethod odSecurityConfiguration
注入自定义实现:
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class SecuredConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new CustomMethodSecurityMetadaSource();
}
}
Spring.version:4.0.5.release Spring security Version:3.2.5.release Spring security oauth版本:2.0.2.release 球衣版本:1.18.1 我想使用Spring security的PreAuthorize注释来保护我的REST API,在这里我定义了被授权访问方法的角色: 当我使用角色为“role_adm
我正在使用来控制的状态,但是我在执行过程中遇到了一个错误。 原因:org.greenrobot.eventbus.事件总线异常:订阅者类maa. Mainactive及其超类没有带有@Subcribe注释的公共方法 无线电经理。JAVA
我有这个问题,无法理解如何修复它,任何帮助都将得到评估。我需要用一些身份验证来保护REST方法,并且我在我的应用程序中有几个角色。我在我的类中的方法中放置了注释,实现了一些接口和Spring没有创建没有任何日志消息的bean(在我的例子中)。但是如果类没有实现接口-bean创建得很好。 在代码中,它如下所示: 控制器: 接口: 在我的情况下,控制器bean没有创建。但是如果我删除一切都会正常工作,
我正在实现来传递和获取来自任何类或片段的数据,并且还订阅了一个方法来获取即时更改的数据...但是我收到了以下错误消息: 组织。绿色机器人。事件巴士。EventBusException:订阅者类java。Boolean及其超类没有带有@Subscribe注释的公共方法 我已经订阅了github在这里展示的方法 代码片段 我只发布了应用程序所需的代码,因为这里不需要其他代码 适配器 更新活动类 新错误
我有一个用Java Spring MVC构建的web应用程序,并使用Spring Security进行登录。登录/退出工作很好。有两个用户角色“role_admin”和“role_user”。 我想确保我的方法只能由具有“role_admin”角色的用户访问。 我添加了批注,如下所示...
我正在使用EventBus创建一个Android应用程序,用于向其他类发布异步广播,但在执行过程中遇到了一个错误。 LogCat显示以下内容: 为什么会这样?我做错什么了吗?