【问题标题】:How to secure a web application with multiple realms using Spring's Java Config?如何使用 Spring 的 Java Config 保护具有多个领域的 Web 应用程序?
【发布时间】:2015-06-15 07:02:52
【问题描述】:

我有一个包含两种资源的网络应用程序。

  • 网页
  • 网络服务

我想使用一个身份验证提供程序(即 CAS)来保护网页,并使用另一个身份验证提供程序(即 BASIC 身份验证)来保护 Web 服务。

我找到了一个可以工作的解决方案here,但它使用 XML,如果可能的话我宁愿不使用 XML 配置。

是否有 Java Config 解决方案?

【问题讨论】:

    标签: java spring spring-security spring-java-config


    【解决方案1】:

    好吧,花了一段时间才弄清楚该怎么做......

    基本上我将我原来的安全配置类拆分成 3 个独立的配置类。

    这基本上是我做的......

    主要的安全配置...

    @Configuration
    @Import({WebPageSecurityConfig.class, WebServiceSecurityConfig.class})
    public class SecurityConfig {
    }
    

    网页的安全配置...(URL不以/service/**开头)

    @Configuration
    @Order(200)
    @EnableWebMvcSecurity
    public class WebPageSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(casAuthenticationProvider());
        }
    
        @Override
        public void configure(final HttpSecurity http) throws Exception {
            http.csrf().disable();
    
            http.requestMatcher(new RequestMatcher() {
                @Override
                public boolean matches(final HttpServletRequest request) {
                    final String url = request.getServletPath() + StringUtils.defaultString(request.getPathInfo());
                    return !(url.startsWith("/service/"));
                }
     });
            http.addFilter(casAuthenticationFilter()).exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint());
            http.authorizeRequests().
                antMatchers("/securedPage").hasAuthority("ROLE_CAS_USER"). // /securedPage can only be accessed by cas user
                anyRequest().permitAll(); // all other pages are unsecured
        }
    
        // General Application Security (CAS Authentication)
    
        @Bean
        public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
            final CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
            casAuthenticationFilter.setAuthenticationManager(authenticationManager());
            return casAuthenticationFilter;
        }
    
        @Bean
        public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
            final CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
            casAuthenticationEntryPoint.setLoginUrl(env.getRequiredProperty("cas.server.url") + "/login");
            casAuthenticationEntryPoint.setServiceProperties(casServiceProperties());
            return casAuthenticationEntryPoint;
        }
    
        @Bean
        public ServiceProperties casServiceProperties() {
            final ServiceProperties serviceProperties = new ServiceProperties();
            serviceProperties.setService(env.getRequiredProperty("cas.service.url") + "/j_spring_cas_security_check");
            serviceProperties.setSendRenew(false);
            return serviceProperties;
        }
    
        @Bean
        public CasAuthenticationProvider casAuthenticationProvider() {
            final CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
            casAuthenticationProvider.setAuthenticationUserDetailsService(casAuthenticationUserDetailsService());
            casAuthenticationProvider.setServiceProperties(casServiceProperties());
            casAuthenticationProvider.setTicketValidator(casTicketValidator());
            casAuthenticationProvider.setKey("casAuthenticationProviderKey");
            casAuthenticationProvider.setStatelessTicketCache(casStatelessTicketCache());
            return casAuthenticationProvider;
        }
    
        @Bean
        public AuthenticationUserDetailsService casAuthenticationUserDetailsService() {
            final AbstractCasAssertionUserDetailsService authenticationUserDetailsService = new AbstractCasAssertionUserDetailsService() {
    
                @Override
                protected UserDetails loadUserDetails(final Assertion assertion) {
                    final String username = assertion.getPrincipal().getName();
                    final List<GrantedAuthority> authorities = new ArrayList<>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_CAS_USER"));                
                    return new User(username, "notused", authorities);
                }
            };
    
            return authenticationUserDetailsService;
        }
    
        @Bean
        public TicketValidator casTicketValidator() {
            final Saml11TicketValidator ticketValidator = new Saml11TicketValidator(env.getRequiredProperty("cas.server.url"));
            ticketValidator.setTolerance(env.getRequiredProperty("cas.ticket.tolerance", Long.class));
            return ticketValidator;
        }
    
        @Bean
        public StatelessTicketCache casStatelessTicketCache() {
            final EhCacheBasedTicketCache ticketCache =  new EhCacheBasedTicketCache();
            ticketCache.setCache(casCache());
            return ticketCache;
        }
    
        @Bean(initMethod = "initialise", destroyMethod = "dispose")
        public Cache casCache() {
            final Cache cache = new Cache("casTickets", 50, true, false, 3600, 900);
            return cache;
        }       
    
        @Autowired
        private Environment env;
    }
    

    RESTful Web 服务的安全配置(URL 以 /service/** 开头)

    @Configuration
    @Order(300)
    @EnableWebMvcSecurity
    public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication().
                withUser("admin").password("password").authorities(new SimpleGrantedAuthority("ROLE_WS_USER"));
        }
    
        @Override
        public void configure(final HttpSecurity http) throws Exception {
            http.csrf().disable();
    
            http.
                antMatcher("/service/**"). // only process URLs that begin with /service/
                sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and(). // RESTful web services are stateless
                addFilter(wsAuthenticationFilter()).exceptionHandling().authenticationEntryPoint(wsAuthenticationEntryPoint());
    
            http.authorizeRequests().anyRequest().hasAuthority("ROLE_WS_USER"); // all requests are secured
        }
    
        // Web Service Security (BASIC Authentication)
    
        @Bean
        public BasicAuthenticationFilter wsAuthenticationFilter() throws Exception {
            final BasicAuthenticationFilter wsAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager(), wsAuthenticationEntryPoint());
            return wsAuthenticationFilter;
        }
    
        @Bean
        public BasicAuthenticationEntryPoint wsAuthenticationEntryPoint() {
            final BasicAuthenticationEntryPoint wsAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
            wsAuthenticationEntryPoint.setRealmName("My Realm");
            return wsAuthenticationEntryPoint;
        }
    
        @Autowired
        private Environment env;
    }
    

    【讨论】:

      【解决方案2】:

      它解释了如何在文档中创建多个证券

      http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#multiple-httpsecurity

      这样的东西应该可以工作

      @EnableWebSecurity
      public class MultiHttpSecurityConfig {
      
          @Configuration
          @Order(1)
          public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
              @Resource private UserDetailsService userBasicAuthService;
      
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/api/**")
                      .userDetailsService(userBasicAuthService)
                      .authorizeRequests()
                      .and()
                      .httpBasic();
              }
          }
      
          @Configuration
          public static class PagesWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
              @Resource private UserDetailsService userCasService;
      
              @Override
              protected void configure(HttpSecurity http) throws Exception {
                  http.antMatcher("/pages/**")
                      .userDetailsService(userCasService)
                      .authorizeRequests()
                      .anyRequest().authenticated()
                      .and()
                      .formLogin();
              }
          }
      
      }
      

      【讨论】:

      • 始终欢迎提供指向潜在解决方案的链接,但请add context around the link,以便您的其他用户知道它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。考虑到仅仅是指向外部站点的链接Why and how are some answers deleted? 的一个可能原因。
      猜你喜欢
      • 2011-03-29
      • 2018-03-08
      • 1970-01-01
      • 2012-03-29
      • 2010-10-17
      • 1970-01-01
      • 2022-08-03
      • 2015-05-12
      • 2014-10-19
      相关资源
      最近更新 更多