Spring security 如何使用Spring安全性和OAuth2保护Apache Camel rest端点

Spring security 如何使用Spring安全性和OAuth2保护Apache Camel rest端点,spring-security,spring-boot,apache-camel,Spring Security,Spring Boot,Apache Camel,我正在开发配置了SSO/OAuth2安全性的Spring引导应用程序。 身份验证对我的rest控制器很有效,现在我需要用rest端点保护我的Apache Camel路由 据我所知,有几种方法可以做到这一点: 通过将身份验证处理器添加到我的路由 通过将策略(SpringSecurityAuthorizationPolicy)添加到我的路由 端点的“按处理程序”选项 我正试图通过向rest端点添加新的身份验证处理器来实现这一点,但我遇到了以下异常: org.springframework.secur

我正在开发配置了SSO/OAuth2安全性的Spring引导应用程序。 身份验证对我的rest控制器很有效,现在我需要用rest端点保护我的Apache Camel路由

据我所知,有几种方法可以做到这一点:

  • 通过将身份验证处理器添加到我的路由
  • 通过将策略(SpringSecurityAuthorizationPolicy)添加到我的路由
  • 端点的“按处理程序”选项
  • 我正试图通过向rest端点添加新的身份验证处理器来实现这一点,但我遇到了以下异常:

    org.springframework.security.oauth2.common.exceptions.OAuth2Exception: 找不到的AuthenticationProvider org.springframework.security.web.authentication.preauthentication.PreAuthenticatedAuthenticationToken

    在调试过程中,我看到org.springframework.security.authentication.ProviderManager.getProviders()只包含一个提供程序AnonymousAuthenticationProvider,因此我可能必须注册相应的提供程序

    有人能帮我找到解决这个问题的正确方法吗

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
      protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().anyRequest().permitAll();
      }
    
      @Configuration
      @EnableResourceServer
      protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    
        @Value("${oauth2.token.endpoint}")
        private String tokenEndpoint;
    
        @Bean
        public ResourceServerTokenServices tokenService() {
          RemoteTokenServices tokenServices = new RemoteTokenServices();
          tokenServices.setClientId("clientId");
          tokenServices.setClientSecret("clientSecret");
          tokenServices.setCheckTokenEndpointUrl(tokenEndpoint);
          return tokenServices;
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests().anyRequest().authenticated();
        }
      }
    
    }
    
    @Configuration
    public class EmbeddedServerRoute {
      @Bean
      public RoutesBuilder embeddedServer() {
        return new RouteBuilder() {
          @Override
          public void configure() throws Exception {
            restConfiguration().component("jetty").port("8081").bindingMode(RestBindingMode.json);
          }
        };
      }
    }
    
    
    @Component
    public class RestTestRoute extends RouteBuilder {
    
      @Autowired
      private AuthProcessor authProcessor;
    
      @Override
      public void configure() throws Exception {
        from("rest:get:/test").process(authProcessor).to("mock:end").end();
      }
    }
    
    
    @Component
    public class AuthProcessor implements Processor {
    
      @Autowired
      private AuthenticationManager authenticationManager;
    
      private TokenExtractor tokenExtractor = new BearerTokenExtractor();
    
      private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new OAuth2AuthenticationDetailsSource();
    
      @Override
      public void process(Exchange exchange) throws Exception {
        HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
        Subject subject = new Subject();
        Authentication auth = getAuth(request);
        subject.getPrincipals().add(auth);
        exchange.getIn().setHeader(Exchange.AUTHENTICATION, subject);
      }
    
      private Authentication getAuth(HttpServletRequest request) throws OAuth2Exception {
        Authentication authentication = null;
        try {
          authentication = tokenExtractor.extract(request);
          if (authentication != null) {
            request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
    
            if (authentication instanceof AbstractAuthenticationToken) {
              AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication;
              needsDetails.setDetails(authenticationDetailsSource.buildDetails(request));
            }
            return authenticationManager.authenticate(authentication);
          }
        } catch (Exception e) {
          throw new OAuth2Exception(e.getMessage());
        }
        throw new OAuth2Exception("Not Authorized to view resource");
      }
    
    }
    
    @配置
    公共类SecurityConfig扩展了WebSecurity配置适配器{
    受保护的无效配置(HttpSecurity http)引发异常{
    http.csrf().disable().authorizeRequests().anyRequest().permitAll();
    }
    @配置
    @EnableResourceServer
    受保护的静态类ResourceServerConfiguration扩展了ResourceServerConfigurerAdapter{
    @值(${oauth2.token.endpoint}”)
    私有字符串标记端点;
    @豆子
    公共资源服务器令牌服务令牌服务(){
    RemoteTokenServices tokenServices=新的RemoteTokenServices();
    tokenServices.setClientId(“clientId”);
    tokenServices.setClientSecret(“clientSecret”);
    setCheckTokenEndpointUrl(tokenEndpoint);
    退货服务;
    }
    @凌驾
    public void configure(HttpSecurity http)引发异常{
    http.authorizeRequests().anyRequest().authorized();
    }
    }
    }
    @配置
    公共类EmbeddedServerRoute{
    @豆子
    公共RoutesBuilder embeddedServer(){
    返回新的RouteBuilder(){
    @凌驾
    public void configure()引发异常{
    restConfiguration().component(“jetty”).port(“8081”).bindingMode(RestBindingMode.json);
    }
    };
    }
    }
    @组成部分
    公共类RestTestRoute扩展了RouteBuilder{
    @自动连线
    专用授权处理器;
    @凌驾
    public void configure()引发异常{
    from(“rest:get:/test”).process(authProcessor).to(“mock:end”).end();
    }
    }
    @组成部分
    公共类AuthProcessor实现处理器{
    @自动连线
    私人AuthenticationManager AuthenticationManager;
    私有TokenExtractor TokenExtractor=新的BealerTokenExtractor();
    私有身份验证DetailsSource AuthenticationDetailsSource=新的OAuth2AuthenticationDetailsSource();
    @凌驾
    公共作废进程(Exchange)引发异常{
    HttpServletRequest=exchange.getIn().getBody(HttpServletRequest.class);
    主题=新主题();
    身份验证auth=getAuth(请求);
    subject.getPrincipals().add(auth);
    exchange.getIn().setHeader(exchange.AUTHENTICATION,subject);
    }
    私有身份验证getAuth(HttpServletRequest请求)引发OAuth2Exception{
    身份验证=空;
    试一试{
    身份验证=tokenExtractor.extract(请求);
    if(身份验证!=null){
    setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE,authentication.getPrincipal());
    if(AbstractAuthenticationToken的身份验证实例){
    AbstractAuthenticationToken需要详细信息=(AbstractAuthenticationToken)身份验证;
    needsDetails.setDetails(authenticationDetailsSource.buildDetails(请求));
    }
    返回authenticationManager.authenticate(身份验证);
    }
    }捕获(例外e){
    抛出新的OAuth2Exception(例如getMessage());
    }
    抛出新的OAuth2Exception(“未授权查看资源”);
    }
    }
    
    作为最终解决方案,我决定使用Spring Boot嵌入式servlet容器,而不是Apache Camel rest组件。因此,它可以很容易地通过Spring Security进行保护。这可以通过创建其他bean来实现:

      @Bean
      public ServletRegistrationBean servletRegistrationBean() {
        SpringServerServlet serverServlet = new SpringServerServlet();
        ServletRegistrationBean regBean = new ServletRegistrationBean(serverServlet, "/camel/*");
        Map<String, String> params = new HashMap<>();
        params.put("org.restlet.component", "restletComponent");
        regBean.setInitParameters(params);
        return regBean;
      }
    
      @Bean
      public Component restletComponent() {
        return new Component();
      }
    
      @Bean
      public RestletComponent restletComponentService() {
        return new RestletComponent(restletComponent());
      }
    
    @Bean
    公共ServletRegistrationBean ServletRegistrationBean(){
    SpringServerServlet=新的SpringServerServlet();
    ServletRegistrationBean regBean=新的ServletRegistrationBean(serverServlet,“/camel/*”);
    Map params=新的HashMap();
    params.put(“org.restlet.component”、“restlecomponent”);
    setInitParameters(参数);
    返回regBean;
    }
    @豆子
    公共组件restlecomponent(){
    返回新组件();
    }
    @豆子
    公共RestletComponent restletComponentService(){
    返回新的restleComponent(restleComponent());
    }