#oauth2安全表达式在方法级别上的应用

16

我应该怎么做才能像下面的例子一样,在方法级别上使用#oauth2安全表达式?

@RequestMapping(value = "email", method = RequestMethod.GET)
  @ResponseBody
  @PreAuthorize("#oauth2.hasScope('read')")
  public String email() {

    return "test@email.com";
  }
如果我请求该资源,我会收到:
    [INFO] java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.hasScope('read')'
[INFO]  at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:14)
[INFO]  at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:44)
[INFO]  at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:57)
[INFO]  at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:25)
[INFO]  at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
[INFO]  at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
[INFO]  at org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor.invoke(AspectJMethodSecurityInterceptor.java:43)
[INFO]  at org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect.ajc$around$org_springframework_security_access_intercept_aspectj_aspect_AnnotationSecurityAspect$1$c4d57a2b(AnnotationSecurityAspect.aj:63)
[INFO]  at pl.insert.controllers.ResourceController.email(ResourceController.java:22)

如果我在ResourceServerConfiguration中指定访问而不是@Controller方法,同样的事情也能很好地发挥作用。

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http.requestMatchers().antMatchers("/oauth/resources/**");
    http.authorizeRequests().anyRequest().access("#oauth2.hasScope('read')");
  }
}

像@PreAuthorize("permitAll")或@PreAuthorize("denyAll")这样的标准安全表达式可以正常工作。因此,可能我需要以某种方式告诉我的AspectJMethodSecurityInterceptor使用OAuth2WebSecurityExpressionHandler。有什么建议吗?


嗨@Marek!你找到解决问题的方法了吗?我这里也有同样的问题... - Sébastien Nussbaumer
很遗憾,就我所记得的,我曾花了一些时间来解决这个问题,但最终发现解决方案过于复杂,不值得实施。我使用@Configuration手动完成此操作:(在我的情况下,这并不太痛苦,但我可以想象有些情况可能会很麻烦。 - Marek Raki
好的,谢谢你的回答。 - Sébastien Nussbaumer
1
我刚刚在这里提交了一个问题:https://github.com/spring-projects/spring-boot/issues/3910 - Sébastien Nussbaumer
@SébastienNussbaumer请查看下面的答案。我刚刚通过解决另一个问题找到了解决方案。对我来说很有效。 - Marek Raki
6个回答

17

为了启用#oAuth2安全表达式,只需要将默认表达式处理程序设置为OAuth2MethodSecurityExpressionHandler,而不是DefaultMethodSecurityExpressionHandler。因为OAuth2MethodSecurityExpressionHandler已经扩展了它,那么整个以前的功能都保持不变。在我的配置中,我同时使用GlobalMethodSecurityConfigurationWebSecurityConfigurerAdapter

@Configuration
@EnableGlobalMethodSecurity
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

  @Override
  protected MethodSecurityExpressionHandler createExpressionHandler() {
    return new OAuth2MethodSecurityExpressionHandler();
  }
}

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  ...
}


@Configuration
@Import({ SecurityConfiguration.class, MethodSecurityConfiguration.class })
public class AppConfiguration {
  ...
}

我有同样的问题。尝试了这个,但没有帮助。能否请有人分享一些源代码? - Ben
2
“it didn't help”是什么意思?@Configuration类已被加载并且createExpressionHandler()方法是否已被调用过?如果是,请在调试器中检查一下你的AspectJMethodSecurityInterceptor是否真正使用了OAuth2MethodSecurityExpressionHandler。如果不是,请调查原因。 - Marek Raki
createExpressionHandler添加覆盖功能对我来说很有效。其他声称只需添加spring-security-oauth2-autoconfigure依赖项的解决方案对我无效(至少在我的单元测试中是如此,没有检查我的应用程序本身)。 - Wim Deblauwe

5
一个更简单的解决方案是让Spring Boot自动配置。 添加以下依赖项即可解决此问题:
compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.4.RELEASE')

我不得不删除与GlobalMethodSecurityConfiguration类相关的配置,并添加了这个依赖项,然后它就正常工作了。 - kelgwiin

5

2

这是一个老问题,现在情况已经改变了。使用Spring Security 5时,应该使用以下方式:

.hasAuthority("SCOPE_scopename")

Spring根据从提供者接收到的范围(以“SCOPE_”为前缀)向主体添加权限。
更多信息请参见:https://www.baeldung.com/spring-security-openid-connect

0

我曾经遇到过同样的问题,但只是在一个单元测试(@WebMvcTest)中。我不得不在为测试定义配置的内部类上添加@EnableGlobalMethodSecurity

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {

  @TestConfiguration
  @Import({JacksonCustomizations.class,SecuritySettings.class,
        OAuth2ServerConfiguration.class, WebSecurityConfiguration.class,
        TokenGrantersConfiguration.class})
  @EnableGlobalMethodSecurity
  public static class TestConfig {
  }
}

更新:在Spring Boot 2.x中,您可能会遇到以下错误:

java.lang.IllegalStateException: 在所有全局方法配置的组合中,实际上没有激活任何注释支持

原因是您添加了@EnableGlobalMethodSecurity,但实际上并没有启用任何内容。要解决此问题,请将注释的至少一个属性设置为true。例如:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

0

对我来说,这是这个答案的结合。

// spring configuration class annotation
@EnableGlobalMethodSecurity(prePostEnabled = true)

并且这个其他答案

// gradle dependencuy
compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.4.RELEASE')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接