SpelEvaluationException 解释 ResourceServerConfigurerAdapter 中的 "access" 字符串
SpelEvaluationException interpreting "access" string in ResourceServerConfigurerAdapter
对此有什么想法吗?
来自 Tomcat:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1011E:(pos 8): Method call: Attempted to call method throwOnError(java.lang.Boolean) on null context object
返回给客户:
java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.throwOnError(#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN'))'
org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:13)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:34)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:18)
org.springframework.security.access.vote.UnanimousBased.decide(UnanimousBased.java:77)
我对我的授权服务器 /oauth/token 执行 POST 并获得一个令牌。
如果我使用该令牌并将 Authorization: Bearer header 添加到对资源服务器的 GET 请求,我会收到该错误。
在我的 ResourceServerConfigurerAdapter 子类中,它炸毁的行在这里:
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
我知道资源服务器可以识别令牌,因为如果我将其遗漏,我会得到正确的错误。如果我编了一个假的,那么我会收到 "invalid token" 消息,这是预期的。如果我使用实际令牌 Spring 会跳入并在 .access()
上爆炸
在此先感谢您的帮助。我将我的 ResourceReserver 的代码放在下面:
@Configuration
@EnableWebSecurity
@EnableResourceServer
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
@Autowired
private OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint;
@Autowired
private ResourceServerTokenServices tokenServices;
@Autowired
private TokenStore tokenStore;
@Autowired
@Qualifier("oauth2ResourceId")
private String oauth2ResourceId;
@Autowired
@Qualifier("oauth2Realm")
private String oauth2Realm;
@Bean
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
final OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setRealmName(oauth2Realm);
entryPoint.setTypeName("Basic");
return entryPoint;
}
private AccessDecisionManager accessDecisionManager() {
return new UnanimousBased(Arrays.<AccessDecisionVoter>asList(new ScopeVoter(),
new AuthenticatedVoter(),
new WebExpressionVoter()));
}
private AuthenticationManager getAuthenticationManager() {
final OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
oAuth2AuthenticationManager.setTokenServices(tokenServices);
return oAuth2AuthenticationManager;
}
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
http
.anonymous()
.disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
http
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.invalidateHttpSession(true);
/*
http
.requiresChannel()
.antMatchers("/oauth/api/**")
.requiresSecure();
http
.portMapper()
.http(8080)
.mapsTo(8443);
*/
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.authenticationManager(getAuthenticationManager())
.tokenServices(tokenServices)
.tokenStore(tokenStore)
.resourceId(oauth2ResourceId);
}
private LogoutSuccessHandler logoutSuccessHandler() {
return new OAuth2SuccessLogoutHandler(tokenStore);
}
static final class OAuth2SuccessLogoutHandler implements LogoutSuccessHandler {
private final TokenStore tokenStore;
public OAuth2SuccessLogoutHandler(final TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.toString();
}
}
}
hasAnyRole()
方法与 OAuth2 无关,因此不在 #oauth2
变量中(它在根目录中,因此您不需要限定它)。
对此有什么想法吗?
来自 Tomcat:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1011E:(pos 8): Method call: Attempted to call method throwOnError(java.lang.Boolean) on null context object
返回给客户:
java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.throwOnError(#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN'))'
org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:13)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:34)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:18)
org.springframework.security.access.vote.UnanimousBased.decide(UnanimousBased.java:77)
我对我的授权服务器 /oauth/token 执行 POST 并获得一个令牌。
如果我使用该令牌并将 Authorization: Bearer header 添加到对资源服务器的 GET 请求,我会收到该错误。
在我的 ResourceServerConfigurerAdapter 子类中,它炸毁的行在这里:
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
我知道资源服务器可以识别令牌,因为如果我将其遗漏,我会得到正确的错误。如果我编了一个假的,那么我会收到 "invalid token" 消息,这是预期的。如果我使用实际令牌 Spring 会跳入并在 .access()
上爆炸在此先感谢您的帮助。我将我的 ResourceReserver 的代码放在下面:
@Configuration
@EnableWebSecurity
@EnableResourceServer
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
@Autowired
private OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint;
@Autowired
private ResourceServerTokenServices tokenServices;
@Autowired
private TokenStore tokenStore;
@Autowired
@Qualifier("oauth2ResourceId")
private String oauth2ResourceId;
@Autowired
@Qualifier("oauth2Realm")
private String oauth2Realm;
@Bean
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
final OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setRealmName(oauth2Realm);
entryPoint.setTypeName("Basic");
return entryPoint;
}
private AccessDecisionManager accessDecisionManager() {
return new UnanimousBased(Arrays.<AccessDecisionVoter>asList(new ScopeVoter(),
new AuthenticatedVoter(),
new WebExpressionVoter()));
}
private AuthenticationManager getAuthenticationManager() {
final OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
oAuth2AuthenticationManager.setTokenServices(tokenServices);
return oAuth2AuthenticationManager;
}
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
http
.anonymous()
.disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
http
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.invalidateHttpSession(true);
/*
http
.requiresChannel()
.antMatchers("/oauth/api/**")
.requiresSecure();
http
.portMapper()
.http(8080)
.mapsTo(8443);
*/
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.authenticationManager(getAuthenticationManager())
.tokenServices(tokenServices)
.tokenStore(tokenStore)
.resourceId(oauth2ResourceId);
}
private LogoutSuccessHandler logoutSuccessHandler() {
return new OAuth2SuccessLogoutHandler(tokenStore);
}
static final class OAuth2SuccessLogoutHandler implements LogoutSuccessHandler {
private final TokenStore tokenStore;
public OAuth2SuccessLogoutHandler(final TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.toString();
}
}
}
hasAnyRole()
方法与 OAuth2 无关,因此不在 #oauth2
变量中(它在根目录中,因此您不需要限定它)。