![](/img/trans.png)
[英]Use @PreAuthorize("#oauth2.hasScope('internal')") with SpringSecurity 5.4.5
[英]Spring Boot 2 @WebMvcTest and OAuth2 #oauth2.hasScope controller causes IllegalArgumentException
這是一個 Spring Boot 2.0.6 應用程序,使用 MVC 控制器使用 @PreAuthorize 和 #oauth2.hasScope 來保護控制器端點。 我已經使用@WebMvcTest 編寫了測試來編寫控制器測試。 似乎正在發出請求,但是當#oauth2.hasScope
被調用時,它沒有給出與某處進行比較的值。 我有什么問題?
例外
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.hasScope('foo')'
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
...
Caused by: java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.hasScope('eq.distributor')'
at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:30)
at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:59)
at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:72)
... 72 more
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method hasScope(java.lang.String) on null context object
at org.springframework.expression.spel.ast.MethodReference.throwIfNotNullSafe(MethodReference.java:153)
at org.springframework.expression.spel.ast.MethodReference.getValueRef(MethodReference.java:82)
... 94 more
測試班
@RunWith(SpringRunner.class)
@WebMvcTest
public class MockMvcTestBase {
@Autowired
protected WebApplicationContext context;
private ObjectMapper objectMapper;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)
.uris()
.withScheme("http")
.withHost("development.com")
.withPort(80))
.alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.apply(springSecurity())
.build();
this.objectMapper = new ObjectMapper();
}
@Test
@WithMockUser(username = "testclient", authorities = "foo")
public void givenValidUser_whenGetOrderDetailsWebEC_thenGetOrder() throws Exception {
getMockMvc().perform(get("/ok")
.header("Authorization", authorizationHeader()))
.andExpect(status().isOk())
.andExpect(content().string("ok"));
}
}
身份驗證配置
@Configuration
@EnableAuthorizationServer
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
@SuppressWarnings("static-method")
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Bean
public static PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("testclient")
.secret("password")
.authorizedGrantTypes("client_credentials")
.accessTokenValiditySeconds(0)
.scopes("foo")
.and()
.withClient("bar")
.secret("password")
.authorizedGrantTypes("client_credentials")
.accessTokenValiditySeconds(0)
.scopes("eq.distributor");
}
}
控制器
@PreAuthorize("#oauth2.hasScope('foo')")
@RequestMapping(value = "/ok", method = RequestMethod.GET)
public String ok() {
return "ok";
}
Spring Security 調試輸出
org.springframework.mock.web.MockHttpServletRequest@54704b46
servletPath:
pathInfo:/ok
headers:
Authorization: Bearer 57962883-e379-433b-b613-1f888471fb84
Accept: application/json;charset=UTF-8
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
OAuth2AuthenticationProcessingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
任何有關我在設置中缺少的內容的幫助都會非常有幫助。 似乎確實有問題,就好像它實際上是在嘗試進行身份驗證一樣,會返回 401/403。 也不例外。 減去進行此編譯所需的更改,這在 Spring Boot 1.5.9 下有效。
如果我為 @SpringBootTest 換出模擬 mvc 注釋,這可以工作,但是我不需要這些測試中的數據庫,所以我想將其設置為不需要加載它。
發生這種情況是因為 Spring 正在使用DefaultMethodSecurityExpressionHandler
。 請參閱: #oauth2 方法級別的安全表達式
要解決此問題,請執行以下操作:
AuthorizationServerConfig
刪除@EnableGlobalMethodSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
對我來說一件重要的事情是,我已經在另一個配置中使用了@EnableGlobalMethodSecurity
,所以 spring 最初忽略了新的配置類
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.