1. 程式人生 > >Spring security oauth2 "no bean resolver registered" 錯誤踩坑

Spring security oauth2 "no bean resolver registered" 錯誤踩坑

Spring security oauth2 “no bean resolver registered” 錯誤踩坑

錯誤堆疊資訊:

java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.throwOnError(@rbacService.hasPermission(request, authentication))'

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1057E: No bean resolver registered in the context to resolve access to bean 'rbacService'

在實現rbac註解時,一開始參考他人程式碼,繼承的是WebSecurityConfigurerAdapter,按如下程式碼執行後,發現帶上token訪問,獲得到的Authentication為匿名使用者(其實是已經使用admin角色使用者登入。)。後參閱資料,猜測可能是注入順序的問題,加上@Order註解後,便修改了繼承類為ResourceServerConfigurerAdapter,便出現上述錯誤堆疊資訊。

import com.jiandian.security.authentication.AuthorizeConfigManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;

@EnableResourceServer
@EnableWebSecurity
@Configuration
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {

    // Todo 這裡應該選擇哪個bean
    @Autowired
    private AuthorizeConfigManager coreAuthorizeConfigManagerImpl;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/hello").permitAll();
        // .anyRequest()
        // .access("@rbacService.hasPermission(request, authentication)");

        coreAuthorizeConfigManagerImpl.config(http.authorizeRequests());
    }
}

在spring的github issue中,找到類似問題。

https://github.com/spring-projects/spring-security-oauth/issues/730#issuecomment-219480394

之後,加入了OAuth2WebSecurityExpressionHandler,在ApiSecurityConfig中加入程式碼,最後完整程式碼如下:

import com.jiandian.security.authentication.AuthorizeConfigManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;

@EnableResourceServer
@EnableWebSecurity
@Configuration
public class ApiSecurityConfig extends ResourceServerConfigurerAdapter {

    // Todo 這裡應該選擇哪個bean
    @Autowired
    private AuthorizeConfigManager coreAuthorizeConfigManagerImpl;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/hello").permitAll()
                .anyRequest()
                 .access("@rbacService.hasPermission(request, authentication)");
    }


    // 之後引入的bean是為了解決no bean resolver registered的問題
    // https://github.com/spring-projects/spring-security-oauth/issues/730#issuecomment-219480394

    @Autowired
    private OAuth2WebSecurityExpressionHandler expressionHandler;
    @Bean
    public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler(ApplicationContext applicationContext) {
        OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
        expressionHandler.setApplicationContext(applicationContext);
        return expressionHandler;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.expressionHandler(expressionHandler);
    }
}