解决处理程序中的异常[public org.springframework.http.ResponseEntity <org.springframework.security.oauth2.common.oauth2accesstoken>

时间:2016-08-17 14:46:37

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

我正在开发 Spring MVC + Spring Security OAuth2 示例。在这个例子中,我将客户端存储在数据库中,并为我的客户端调用检索它,它给了我错误。不确定为什么不必要它作为客户端寻找用户名和密码值?请参考源代码:https://github.com/rajithd/spring-security-oauth2-rest。我刚刚更新了spring和security依赖关系到最新版本和spring-security.xml文件更新。

DEBUG o.s.s.a.DefaultAuthenticationEventPublisher - No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException
DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException]: org.springframework.security.authentication.InternalAuthenticationServiceException: Incorrect result size: expected 1, actual 0
DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Invoking @ExceptionHandler method: public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.exceptions.OAuth2Exception> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.handleException(java.lang.Exception) throws java.lang.Exception
INFO  o.s.s.o.p.endpoint.TokenEndpoint - Handling error: InternalAuthenticationServiceException, Incorrect result size: expected 1, actual 0
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Serializer'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Serializer'
DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@2b1377
DEBUG o.s.w.s.m.m.a.HttpEntityMethodProcessor - Written [error="unauthorized", error_description="Incorrect result size: expected 1, actual 0"] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@144e43a]
DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

OauthRepository.java

@Repository
public class OauthRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private final static String FETCH_BY_USERNAME = "select username,password from auth_details where username=?";

    private final static String FETCH_BY_CLIENT_ID = "select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details where client_id = ?";

    public User getByUsername(String username) {
        return jdbcTemplate.queryForObject(FETCH_BY_USERNAME, new Object[]{username}, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet resultSet, int i) throws SQLException {
                User user = new User(resultSet.getString("username"), resultSet.getString("password"), Collections.<GrantedAuthority>emptyList());
                return user;
            }
        });
    }

    public BaseClientDetails getByClientId(String clientId) {
        return jdbcTemplate.queryForObject(FETCH_BY_CLIENT_ID, new Object[]{clientId}, new RowMapper<BaseClientDetails>() {
            @Override
            public BaseClientDetails mapRow(ResultSet rs, int i) throws SQLException {
                BaseClientDetails details = new BaseClientDetails(rs.getString(1), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(7), rs.getString(6));
                details.setClientSecret(rs.getString(2));
                if (rs.getObject(8) != null) {
                    details.setAccessTokenValiditySeconds(Integer.valueOf(rs.getInt(8)));
                }

                if (rs.getObject(9) != null) {
                    details.setRefreshTokenValiditySeconds(Integer.valueOf(rs.getInt(9)));
                }

                String scopes1 = rs.getString(11);
                if (scopes1 != null) {
                    details.setAutoApproveScopes(StringUtils.commaDelimitedListToSet(scopes1));
                }
                return details;
            }
        });
    }
}

ClientService.java

@Component
public class ClientService implements ClientDetailsService {

    @Autowired
    private OauthRepository oauthRepository;

    @Override
    public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException {
        System.out.println("Load Client :"+ s);
        BaseClientDetails clientDetails = oauthRepository.getByClientId(s);
        return clientDetails;
    }
}

UserService.java

@Component
public class UserService implements UserDetailsService {

    @Autowired
    private OauthRepository oauthRepository;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = oauthRepository.getByUsername(s);
        return user;
    }
}

弹簧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"
       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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <http pattern="/oauth/token" auto-config="true"  use-expressions="true" 
          create-session="stateless" 
          authentication-manager-ref="clientAuthenticationManager"
          xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/oauth/token" access="permitAll"/>
        <anonymous enabled="false"/>
        <http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
        <!-- include this only if you need to authenticate clients via request parameters -->
        <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
        <access-denied-handler ref="oauthAccessDeniedHandler"/>
        <sec:csrf disabled="true" />
    </http>

    <!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
       separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
    <http pattern="/test/*"  auto-config="true"  use-expressions="true" 
          create-session="never" 
          entry-point-ref="oauthAuthenticationEntryPoint"
          access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false"/>
        <intercept-url pattern="/test/*" access="hasRole('ROLE_USER')"  />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
        <access-denied-handler ref="oauthAccessDeniedHandler"/>
         <sec:csrf disabled="true" />
    </http>

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

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

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

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

    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
          xmlns="http://www.springframework.org/schema/beans">
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
                <bean class="org.springframework.security.access.vote.RoleVoter"/>
                <bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
                <bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
            </list>
        </constructor-arg>
    </bean>

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

    <bean id="passwordEncoder"  class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
        <constructor-arg name="strength" value="11"/>
    </bean>

    <authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
        <authentication-provider user-service-ref="userService">
            <password-encoder ref="passwordEncoder"/>
        </authentication-provider>
    </authentication-manager>

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

    <!-- Used for the persistenceof tokens (currently an in memory implementation) -->
    <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
        <constructor-arg ref="dataSource"/>
    </bean>

    <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="clientDetails"/>
    </bean>

    <bean id="oAuth2RequestFactory"
          class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
        <constructor-arg ref="clientDetails"/>
    </bean>

    <bean id="userApprovalHandler"
          class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
        <property name="tokenStore" ref="tokenStore"/>
        <property name="requestFactory" ref="oAuth2RequestFactory"/>
    </bean>


    <!-- authorization-server aka AuthorizationServerTokenServices is an interface that defines everything necessary for token management -->
    <oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
                                user-approval-handler-ref="userApprovalHandler">
        <oauth:authorization-code/>
        <oauth:implicit/>
        <oauth:refresh-token/>
        <oauth:client-credentials/>
        <oauth:password/>
    </oauth:authorization-server>

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

    <bean id="clientDetails" class="org.ateam.common.service.ClientService" />

    <sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
        <!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->
        <sec:expression-handler ref="oauthExpressionHandler"/>
    </sec:global-method-security>

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

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

</beans>

db.sql

DROP TABLE IF EXISTS auth_details;
CREATE TABLE auth_details (
  username varchar(256),
  password varchar(256),
  PRIMARY KEY (username)
) ENGINE=InnoDB ;

-- rajith/password
insert into auth_details values('rajith','$2a$11$gxpnezmYfNJRYnw/EpIK5Oe08TlwZDmcmUeKkrGcSGGHXvWaxUwQ2');

DROP TABLE IF EXISTS oauth_client_details;
CREATE TABLE oauth_client_details (
  client_id varchar(256) NOT NULL,
  resource_ids varchar(256) DEFAULT NULL,
  client_secret varchar(256) DEFAULT NULL,
  scope varchar(256) DEFAULT NULL,
  authorized_grant_types varchar(256) DEFAULT NULL,
  web_server_redirect_uri varchar(256) DEFAULT NULL,
  authorities varchar(256) DEFAULT NULL,
  access_token_validity int(11) DEFAULT NULL,
  refresh_token_validity int(11) DEFAULT NULL,
  additional_information varchar(4096) DEFAULT NULL,
  autoapprove varchar(4096) DEFAULT NULL,
  PRIMARY KEY (client_id)
);

INSERT INTO oauth_client_details(client_id, resource_ids, client_secret, scope, authorized_grant_types, authorities, access_token_validity, refresh_token_validity)
VALUES ('rajith-client-id', 'rest_api', '12345', 'trust,read,write', 'password,authorization_code,refresh_token,implicit', 'ROLE_USER', '5', '1000');

DROP TABLE IF EXISTS oauth_access_token;

CREATE TABLE oauth_access_token (
  token_id varchar(256) DEFAULT NULL,
  token blob,
  authentication_id varchar(256) DEFAULT NULL,
  user_name varchar(256) DEFAULT NULL,
  client_id varchar(256) DEFAULT NULL,
  authentication blob,
  refresh_token varchar(256) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


DROP TABLE IF EXISTS oauth_refresh_token;

CREATE TABLE oauth_refresh_token (
  token_id varchar(256) DEFAULT NULL,
  token blob,
  authentication blob
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

的pom.xml

<properties>
        <jdk-version>1.8</jdk-version>
        <maven-compiler-plugin>3.0</maven-compiler-plugin>
        <maven-war-pugin>2.4</maven-war-pugin>

        <org.springframework.version>4.3.1.RELEASE</org.springframework.version>
        <hibernate>4.3.6.Final</hibernate>
        <spring-security-oauth2>2.0.10.RELEASE</spring-security-oauth2>
        <spring.security.version>4.1.1.RELEASE</spring.security.version>
        <jersey-spring>1.18.1</jersey-spring>
        <servlet-version>3.0.1</servlet-version>

        <logback.version>1.1.7</logback.version>
        <jcl-over-slf4j.version>1.7.21</jcl-over-slf4j.version>
    </properties>

    <dependencies>
        <!-- Spring web dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!-- Spring security Dependencies -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-aspects</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
        </dependency>

        <!-- for OAuth 2.0 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>${spring-security-oauth2}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Hibernate Dependencies -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.31</version>
        </dependency>


        <!-- Jersey Spring Integration -->
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-spring</artifactId>
            <version>${jersey-spring}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-web</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-spring}</version>
        </dependency>

        <!-- Added java.lang.IllegalArgumentException: No converter found for return value of type: -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
        </dependency>

        <!-- logging, slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${jcl-over-slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <!--Start Servlet Dependencies -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet-version}</version>
        </dependency>

CURL输出:

D:\>curl -vvv -X POST "http://localhost:8080/oauth2/oauth/token?grant_type=password&client_id=rajith-client-id&client_secret=12345&username=rajith&password=password"
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /oauth2/oauth/token?grant_type=password&client_id=rajith-client-id&client_secret=12345&username=rajith&password=password HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.46.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< Cache-Control: no-store
< Pragma: no-cache
< WWW-Authenticate: Bearer error="unauthorized", error_description="Incorrect result size: expected 1, actual 0"
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2016 14:40:09 GMT
<
{"error":"unauthorized","error_description":"Incorrect result size: expected 1, actual 0"}* Connection #0 to host localhost left intact

0 个答案:

没有答案