如何在Spring-Security-OAuth2中使用WebSecurity适配器

时间:2017-03-27 07:59:19

标签: spring spring-boot spring-security spring-security-oauth2

我正在尝试使用OAuth2以及简单的Spring Security(Web安全适配器)来实现身份验证系统。但是当我尝试配置时,我无法同时使用这两种服务。根据下面分享的配置文件代码,但它可以使用弹簧安全性(Web安全适配器)使用OAuth2或简单身份验证。我希望身份验证系统都能基于URL识别工作。

提前致谢!

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class ConfigurationClass {

    // Its working as simple auth spring security 
    @EnableWebSecurity
    @Configuration
    @Order(1)
    protected static class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserDetailsService userDetailsService;

        @Autowired
        private TokenAuthenticationService tokenAuthenticationService;

        @Autowired
        private OtpManage OtpManage;

        @Autowired
        private RoleRepository RoleRepository;

        public StatelessAuthenticationSecurityConfig() {
            super(true);

        }


        @Override
        protected void configure(HttpSecurity http) throws Exception {

            // allow anonymous resource requests
            .antMatchers("/").permitAll()

            // allow anonymous POSTs to login
            .antMatchers(HttpMethod.POST, "/user/registration").permitAll()
            .antMatchers(HttpMethod.POST, "/user/changepassword").permitAll()
            .antMatchers(HttpMethod.POST, "/user/resetpassword").permitAll()
            // .antMatchers(HttpMethod.POST,
            // "/api/otpResetPassword").permitAll()
            .antMatchers(HttpMethod.POST, "/user/saveusergroup").permitAll()
            .antMatchers(HttpMethod.POST, "/user/bugreport").permitAll()
            .antMatchers(HttpMethod.POST, "/user/createtoken").permitAll()

            // .anyRequest().authenticated().and()
            .anyRequest().hasAnyRole("USER","SYSTEM_ADMIN","ADMIN").and()

            // custom JSON based authentication by POST of
            // {"username":"<name>","password":"<password>"} which sets the
            // token header upon authentication
            .addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, userDetailsService,
                    authenticationManager(), OtpManage), UsernamePasswordAuthenticationFilter.class)


            // custom Token based authentication based on the header
            // previously given to the client
            .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
                    UsernamePasswordAuthenticationFilter.class);


        }

        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
        }

        @Override
        protected UserDetailsService userDetailsService() {
            return userDetailsService;
        }

    }

    // Its not working, But if I removed @Order(1) annotation from StatelessAuthenticationSecurityConfig class then this one will work as default
    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Autowired
        private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

        @Autowired
        private CustomLogoutSuccessHandler customLogoutSuccessHandler;

        @Override
        public void configure(HttpSecurity http) throws Exception {
            System.out.println("@EnableResourceServer");
            http
                    .exceptionHandling()
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .and()
                    .logout()
                    .logoutUrl("/oauth/logout")
                    .logoutSuccessHandler(customLogoutSuccessHandler)
                    .and()
                    .csrf()
                    .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
                    .disable()
                    .headers()
                    .frameOptions().disable().disable()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/hello/").permitAll()
                    .antMatchers("/secure/**").authenticated();

        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {

        private static final String ENV_OAUTH = "authentication.oauth.";
        private static final String PROP_CLIENTID = "clientid";
        private static final String PROP_SECRET = "secret";
        private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";

        private RelaxedPropertyResolver propertyResolver;

        @Autowired
        private DataSource dataSource;

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints
                    .tokenStore(tokenStore())
                    .authenticationManager(authenticationManager);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            System.out.println("@AuthorizationServerConfigurerAdapter");
            clients
                    .inMemory()
                    .withClient(propertyResolver.getProperty(PROP_CLIENTID))
                    .scopes("read", "write")
                    .authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
                    .authorizedGrantTypes("password", "refresh_token")
                    .secret(propertyResolver.getProperty(PROP_SECRET))
                    .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
        }

        @Override
        public void setEnvironment(Environment environment) {
            this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
        }

    }

}

更新

我使用 @ EnableOAuth2Client,@ Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)对我的代码进行了一些更改,我已经实现了我想要做的事情。但现在问题是我无法使用用户凭据调用发布网址:“/ api / login”。我收到错误 url not found 。根据我在WebSecurityConfig类中的代码,我在loginFilter类的configure(HttpSecurity http)方法中添加了filter,它扩展了AbstractAuthenticationProcessingFilter。但是这个用“/ api / login”url映射的过滤器根本不起作用。为什么这个过滤器不起作用我不明白。有人可以帮助我。

#WebSecurityConfigClass

/**
 * Implementation of HttpSecurity configure method
 * Implementation custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
 * @author Santosh
 *
 */
@EnableOAuth2Client
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled = true, proxyTargetClass = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;

    @Autowired
    private MessageSource messages;

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;

    @Autowired
    private RESTAuthenticationFailureHandler restAuthenticationFailureHandler;

    @Autowired
    private CustomAccessDeniedHandler accessDeniedHandler;

    public WebSecurityConfig() {
        super(true);
    }

    /*@Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("testUser").password("testUser").roles("USER");
    }
*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // setup security
        http
        .exceptionHandling()
        .accessDeniedHandler(accessDeniedHandler)
        .authenticationEntryPoint(authenticationEntryPoint)
        .and()
        .authorizeRequests()
            .anyRequest()
                .fullyAuthenticated()
                .and().httpBasic();

        http
        .exceptionHandling()
        .accessDeniedHandler(accessDeniedHandler)
        .authenticationEntryPoint(authenticationEntryPoint)
        .and()
        .anonymous().and()
        .servletApi().and()
        .headers().and()
        .authorizeRequests()
        .antMatchers(HttpMethod.POST, "/api/login").permitAll()

        .antMatchers("/admin/**").hasRole("ADMIN")
        .and()
        .authorizeRequests()
        .anyRequest().hasAnyRole("USER").and()
        //all other request need to be authenticated
        // custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
        .addFilterBefore(new LoginFilter("/api/login", tokenAuthenticationService, userDetailsService, authenticationManager(), restAuthenticationSuccessHandler, restAuthenticationFailureHandler), UsernamePasswordAuthenticationFilter.class)
        // custom Token based authentication based on the header previously given to the client
        .addFilterBefore(new ApplicationFilter (tokenAuthenticationService, messages), UsernamePasswordAuthenticationFilter.class);

    }

//   To allow Pre-flight [OPTIONS] request from browser 
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
        web.ignoring()//allow anonymous GETs to API
        .antMatchers(HttpMethod.GET, "/api/status/**");
    }

    @Bean 
    public RequestContextListener requestContextListener(){
        return new RequestContextListener();
    } 

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }

    @Bean(name="authenticationManagerBean")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

#OAuth2ServerConfiguration

@Configuration
public class OAuth2ServerConfiguration {

    private static final String RESOURCE_ID = "restservice";
    private static final String ROLE_ADMIN = "ADMIN";

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Autowired
        private CustomOAuth2AccessDeniedHandler accessDeniedHandler;

        @Autowired
        private RESTOAuth2AuthenticationEntryPoint restAuthenticationEntryPoint;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.resourceId(RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {

            http
            .authorizeRequests()
            .antMatchers("/api/hello").permitAll()
            .antMatchers("/users/current/**","/oauth/token","/oauth/authorize","/oauth/refresh_token").permitAll()
            .antMatchers("/api/greeting").authenticated().and().exceptionHandling()
                    .accessDeniedHandler(accessDeniedHandler)
                    .authenticationEntryPoint(restAuthenticationEntryPoint);
        }


    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private UserDetailsService userDetailsService;

        @Autowired
        private DataSource dataSource;

        @Autowired
        private TokenStore tokenStore;

        @Bean
        public TokenStore tokenStore() {
             return new JdbcTokenStore(dataSource);
        }

//      @Autowired
//      private UserApprovalHandler userApprovalHandler;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

            endpoints.tokenStore(this.tokenStore).authenticationManager(this.authenticationManager)
                    .userDetailsService(userDetailsService);
//          .userApprovalHandler(userApprovalHandler)
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//          jdbc(dataSource)
            clients.inMemory().withClient("clientapp").authorizedGrantTypes("password", "refresh_token")
                    .authorities("USER").scopes("read", "write").resourceIds(RESOURCE_ID).secret("123456")
                    .accessTokenValiditySeconds(20)// Access token is only valid
                                                    // for 2 minutes.
                    .refreshTokenValiditySeconds(1200);// Refresh token is only
                                                        // valid for 10
                                                        // minutes.;

        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(this.tokenStore);
            return tokenServices;
        }

    }

}

1 个答案:

答案 0 :(得分:0)

在您的WebSecurityAdapter上构建requestMatchers以确定HttpSecurity实例将调用哪些请求。

例如:

protected void configure(HttpSecurity http) throws Exception {
  http.requestMatchers().antMatchers("/secure/path", "/more/secure/path");
  // Rest of your configuration.
}