Spring OAuth2问题

时间:2015-05-13 16:14:57

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

我正在将基于xml的配置(从source)转换为java配置。我已将这两个文件放在下面,它正在使用xml配置,但在更改为java配置后无法进行身份验证。任何人都可以提出一些如何解决它的想法吗?

认证managers.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://www.springframework.org/schema/security"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans.xsd
                      http://www.springframework.org/schema/security
                      http://www.springframework.org/schema/security/spring-security.xsd">

    <bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>

    <sec:authentication-manager alias="userAuthenticationManager">
        <sec:authentication-provider user-service-ref="userService">
            <sec:password-encoder ref="passwordEncoder"/>
        </sec:authentication-provider>
    </sec:authentication-manager>

    <sec:authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
        <sec:authentication-provider user-service-ref="client-details-user-service"/>
    </sec:authentication-manager>


    <bean id="client-details-user-service" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
        <constructor-arg ref="client-details-service" />
    </bean>

</beans>

端点-configuration.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans.xsd
                      http://www.springframework.org/schema/security
                      http://www.springframework.org/schema/security/spring-security.xsd">



    <http pattern="/v1.0/users" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
          xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/v1.0/users" method="POST" access="IS_AUTHENTICATED_FULLY"/>
        <anonymous enabled="false"/>
        <http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
        <access-denied-handler ref="oauthAccessDeniedHandler"/>
    </http>


    <!-- REST API Endpoints -->
    <http pattern="/v1.0/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
          xmlns="http://www.springframework.org/schema/security">
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
        <access-denied-handler ref="oauthAccessDeniedHandler"/>
    </http>


</beans>

security.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <context:component-scan base-package="com.porterhead.oauth2.configuration"/>


    <!-- Access voters -->
    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
          xmlns="http://www.springframework.org/schema/beans">
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
    </bean>

    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                ROLE_ADMIN > ROLE_USER
                ROLE_USER > ROLE_GUEST
            </value>
        </property>
    </bean>

    <bean id="roleVoter" class="com.porterhead.security.HierarchicalJsr250Voter">
        <constructor-arg ref="roleHierarchy" />
    </bean>

    <sec:global-method-security jsr250-annotations="enabled" access-decision-manager-ref="accessDecisionManager"/>

    <oauth:expression-handler id="oauthExpressionHandler"/>

    <oauth:web-expression-handler id="oauthWebExpressionHandler"/>

</beans>

Oauth2 config

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
       xmlns:sec="http://www.springframework.org/schema/security"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans.xsd
                      http://www.springframework.org/schema/security/oauth2
                      http://www.springframework.org/schema/security/spring-security-oauth2.xsd
                      http://www.springframework.org/schema/security
                      http://www.springframework.org/schema/security/spring-security.xsd">


    <oauth:authorization-server client-details-service-ref="client-details-service" token-services-ref="tokenServices">
        <oauth:refresh-token/>
        <oauth:password/>
    </oauth:authorization-server>

    <oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices"/>

    <bean id="clientCredentialsTokenEndpointFilter"
          class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <property name="authenticationManager" ref="clientAuthenticationManager"/>
    </bean>

    <bean id="clientAuthenticationEntryPoint"
          class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="typeName" value="Basic"/>
    </bean>

    <bean id="oauthAuthenticationEntryPoint"
          class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="test"/>
    </bean>

    <bean id="oauthAccessDeniedHandler"
          class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>


    <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
        <property name="tokenStore" ref="tokenStore"/>
        <property name="supportRefreshToken" value="true"/>
        <property name="clientDetailsService" ref="client-details-service"/>
    </bean>

    <bean id="corsFilter" class="com.porterhead.filter.spring.SpringCrossOriginResourceSharingFilter"/>

    <bean id="oauthRestEntryPoint" class="com.porterhead.security.OAuthRestEntryPoint"/>

    <!-- The token endpoint See org.springframework.security.oauth2.provider.endpoint.TokenEndpoint-->
    <http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
          xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false"/>
        <http-basic entry-point-ref="oauthRestEntryPoint" />
        <access-denied-handler ref="oauthAccessDeniedHandler"/>
        <custom-filter ref="corsFilter" after="LAST"/>
    </http>


</beans>

转换后基于JAVA的配置

oauth2 config

@Configuration
@ComponentScan
@EnableResourceServer
@Import(SecurityConfig.class)
//@ImportResource({
//  "classpath:META-INF/spring/oauth/client-details.xml"
//})
public class OAuth2ServerConfig {

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends
            AuthorizationServerConfigurerAdapter {


        @Autowired
        private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(){
            ClientCredentialsTokenEndpointFilter clientFilter = new ClientCredentialsTokenEndpointFilter();
            return clientFilter;
        }

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Autowired
        public OAuth2AccessTokenRepository oAuth2AccessTokenRepository;

        @Autowired
        public OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;

        @Bean
        public DefaultTokenServices tokenServices(){
            final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setReuseRefreshToken(true);
            defaultTokenServices.setTokenStore(tokenStore());
            defaultTokenServices.setClientDetailsService(clientDetailsService);
            return defaultTokenServices;
        }

        @Bean
        public OAuth2RepositoryTokenStore tokenStore() {
            return new OAuth2RepositoryTokenStore(oAuth2AccessTokenRepository,
                    oAuth2RefreshTokenRepository);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer)
                throws Exception {
            oauthServer.tokenKeyAccess(
                    "isAnonymous || hasAuthority('ROLE_TRUSTED_CLIENT')")
                    .realm("test");
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients)
                throws Exception {
            clients.withClientDetails(clientDetailsService);
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints.tokenServices(tokenServices())
                    .setClientDetailsService(clientDetailsService);
        }
    }

}

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private Validator validator;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new StandardPasswordEncoder();
    }
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserServiceImpl(userRepository, validator, passwordEncoder());
    }

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService());
    }
    @Bean
    public OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler(){
        return new OAuth2AccessDeniedHandler();
    }

    @Configuration
    @Order(1)
    public static class OAuthEndPointConfig extends WebSecurityConfigurerAdapter{


        @Autowired
        private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Bean
        public OAuthRestEntryPoint oauthRestEntryPoint()
        {
            return new OAuthRestEntryPoint();
        }

        @Bean
        public ClientDetailsUserDetailsService clientDetailsUserDetailsService(){
            return new ClientDetailsUserDetailsService(clientDetailsService);
        }


        @Bean
        protected AuthenticationEntryPoint authenticationEntryPoint(){
            OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
            entryPoint.setTypeName("Basic");
            entryPoint.setRealmName("test");
            return entryPoint;
        }



        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.anonymous().disable()
                .antMatcher("/oauth/token")
                .anonymous().disable().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .httpBasic().authenticationEntryPoint(oauthRestEntryPoint())
            .and()
                .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/token")).disable()
                .exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
            .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

            ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
            filter.setAuthenticationManager(authenticationManagerBean());
            filter.afterPropertiesSet();
        }


    }
    @Configuration
    @Order(2)
    protected static class ResourceServerEndpointConfig extends WebSecurityConfigurerAdapter{

        @Autowired
        private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
        @Bean
        public OAuth2AuthenticationEntryPoint clientAuthenticationEntryPoint(){
            OAuth2AuthenticationEntryPoint clientAuthenticationEntrypoint = new OAuth2AuthenticationEntryPoint();
            clientAuthenticationEntrypoint.setTypeName("Basic");
            return clientAuthenticationEntrypoint;
        }


        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.anonymous().disable().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
                .authenticationEntryPoint(clientAuthenticationEntryPoint())
            .and()
                .requestMatchers().antMatchers("/v1.0/users")
            .and()
                .authorizeRequests().antMatchers(HttpMethod.POST, "/v1.0/users").permitAll()
            .and()
                .csrf().disable();
        }
    }


}

转换后的输出

curl -v -X POST    -H "Content-Type: application/json"    -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM="    -d '{"user":{"emailAddress":"user@example.com"}, "password":"password"}'    'http://localhost:8080/v1.0/users'
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /v1.0/users HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=
> Content-Length: 67
>
* upload completely sent off: 67 out of 67 bytes
< HTTP/1.1 401 Unauthorized
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Cache-Control: no-store
< Pragma: no-cache
< WWW-Authenticate: Basic realm="oauth", error="unauthorized", error_description="An Authentication object was not found in the SecurityContext"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 13 May 2015 16:01:40 GMT
<
* Connection #0 to host localhost left intact
{"error":"unauthorized","error_description":"An Authentication object was not found in the SecurityContext"}Veeras-MacBook-Pro:~ veeramarni$

1 个答案:

答案 0 :(得分:2)

我认为authenticationManager中自动装配的OAuth2ServerConfig实例会使用默认DaoAuthenticationProvider进行初始化。要使用已定义的自定义bean,请注入自定义bean,配置AuthenticationManagerBuilder并在authenticationManager中将SecurityConfig公开为bean,如下所示

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
@Qualifier("userDetailsManagerImpl")
private UserDetailsManager userDetailsManager;

....
....

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

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.parentAuthenticationManager(authenticationManager);
    auth.userDetailsService(userDetailsManager);
}

同样在OAuth2ServerConfig中注入新暴露的bean并按如下所示进行配置

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

...
...

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
        throws Exception {
    endpoints.authenticationManager(authenticationManager)
    .setClientDetailsService(clientDetailsService);
    .tokenServices(tokenServices());

}

希望这会有所帮助。