【问题标题】:How to use WebSecurity adapter with Spring-Security-OAuth2如何将 WebSecurity 适配器与 Spring-Security-OAuth2 一起使用
【发布时间】:2017-08-19 20:00:40
【问题描述】:

我正在尝试使用 OAuth2 以及简单的 Spring Security(Web 安全适配器)来实现身份验证系统。但是当我尝试配置时,我无法同时使用这两种服务。根据下面共享的配置文件代码,但它可以使用 OAuth2 或使用 spring security(Web 安全适配器)的简单身份验证。我希望两个身份验证系统都应该基于 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) 对我的代码进行了一些更改,并且我已经实现了我想要做的事情。但现在的问题是我无法使用用户凭据调用发布 url: "/api/login" 。我收到错误,因为 url not found。根据我在 WebSecurityConfig 类中的代码,我在扩展 AbstractAuthenticationProcessingFilter 的 loginFilter 类的 configure(HttpSecurity http) 方法中添加了过滤器。但是这个用“/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;
        }

    }

}

【问题讨论】:

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


    【解决方案1】:

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

    例如:

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

    【讨论】:

    • 您好 Bart,我正在使用单独的两种适配器,第一种是 WebSecurityConfig 类,第二种是 OAuth2ServerConfiguration 类,所以,如果我调用第二种适配器 http 对象,它没有被调用,但在制作之后其工作方式几乎没有变化。现在问题出在第一个适配器中,我使用 addFilterBefore() 方法调用扩展 AbstractAuthenticationProcessingFilter 的类。它根本不起作用。请在同一问题的更新部分查看更多详细信息
    猜你喜欢
    • 1970-01-01
    • 2019-05-27
    • 2014-12-11
    • 2019-09-25
    • 2016-09-04
    • 2018-04-14
    • 2022-01-01
    • 2020-11-02
    • 2021-09-03
    相关资源
    最近更新 更多