没有注册bean解析器

roy*_*oyB 6 spring spring-security spring-boot

今天升级Spring boot 1.2.51.3.0 BUILD-SNAPSHOTCalling @PreAuthorize失败后:

例:

@PreAuthorize("@defaultSecurityService.canDoSomething(authentication.principal.id, #objId)")
Result doSomething(@P("objId")String objId);
Run Code Online (Sandbox Code Playgroud)

其中defaultSecurityService定义为:

@Service
public class DefaultSecurityService implements SecurityService {
    ...
    public boolean canDoSomething(String userId, String objId){
        return true; // 
    }
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪

Caused by: java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.throwOnError(defaultSecurityService.canDoSomething(authentication.principal.id, #objId))'
at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:14)
...
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 8): No bean resolver registered in the context to resolve access to bean 'defaultSecurityService'
Run Code Online (Sandbox Code Playgroud)

我试过的:

make SecurityServiceextend [PermissionEvaluator ][1] and register a bean atApplication.java`

 @Bean
 @Lazy
 public PermissionEvaluator permissionEvaluator(){
     return securityService;
 }`
Run Code Online (Sandbox Code Playgroud)

但我仍然得到同样的错误

阅读spring security 4.0.2文档并未透露任何有关重大变更的相关资料

Rob*_*nch 5

这似乎是新添加的OAuth2AutoConfiguration中错误.具体地说,它带来了OAuth2MethodSecurityConfiguration将覆盖与不具有集.DefaultMethodSecurityExpressionHandlerOAuth2MethodSecurityExpressionHandlerBeanResolver

如果您不使用OAuth2,那么最简单的解决方案是从类路径中删除Spring Security OAuth.

或者,OAuth2AutoConfiguration如果您使用以下内容,则可以排除使用以下内容@SpringBootApplication:

@SpringBootApplication(exclude=OAuth2AutoConfiguration.class)
Run Code Online (Sandbox Code Playgroud)

或者,如果@AutoConfiguration直接利用,您可以使用以下内容:

@AutoConfiguration(exclude=OAuth2AutoConfiguration.class)
Run Code Online (Sandbox Code Playgroud)

UPDATE

你也可以使用这样的东西:

public class DelegatingMethodSecurityExpressionHandler implements
        MethodSecurityExpressionHandler {

    private final MethodSecurityExpressionHandler delegate;

    public DelegatingMethodSecurityExpressionHandler(
            MethodSecurityExpressionHandler delegate) {
        super();
        this.delegate = delegate;
    }

    public Object filter(Object filterTarget, Expression filterExpression,
            EvaluationContext ctx) {
        return delegate.filter(filterTarget, filterExpression, ctx);
    }

    public ExpressionParser getExpressionParser() {
        return delegate.getExpressionParser();
    }

    public EvaluationContext createEvaluationContext(
            Authentication authentication, MethodInvocation invocation) {
        return delegate.createEvaluationContext(authentication, invocation);
    }

    public void setReturnObject(Object returnObject, EvaluationContext ctx) {
        delegate.setReturnObject(returnObject, ctx);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的配置中使用:

@Autowired(required = false)
List<AuthenticationTrustResolver> trustResolvers = new ArrayList<>();

@Autowired(required = false)
List<PermissionEvaluator> permissionEvaluators = new ArrayList<>();

@Bean
public MethodSecurityExpressionHandler securityExpressionHandler(ApplicationContext context) {
    OAuth2MethodSecurityExpressionHandler delegate = new OAuth2MethodSecurityExpressionHandler();
    delegate.setApplicationContext(context);
    if(trustResolvers.size() == 1) {
        delegate.setTrustResolver(trustResolvers.get(0));
    }
    if(permissionEvaluators.size() == 1) {
        delegate.setPermissionEvaluator(permissionEvaluators.get(0));
    }
    return new DelegatingMethodSecurityExpressionHandler(delegate);
}
Run Code Online (Sandbox Code Playgroud)

我们必须将它包装在DelegatingMethodSecurityExpressionHandler中,因为Spring Boot的自动配置将替换DefaultMethodSecurityExpressionHandler具有损坏配置的任何子类.