【问题标题】:Getting invalid scope when requesting for oauth2 access token请求 oauth2 访问令牌时获取无效范围
【发布时间】:2016-11-08 01:35:15
【问题描述】:

我的服务器中有一个 oauth 服务,它执行身份验证操作并在对有效用户发出请求时发出访问令牌。然后,当我尝试使用命令行 curl 请求向该服务请求时,我遇到了错误。

"detailMessage":"Invalid scope: read,write,trust","cause":{"additionalInformation":{"scope":"read trust write"}

以下是我的请求导致错误。

curl -X POST http://localhost:8080/MyProjectOauth/oauth/token -H “Accept: application/json” -d "grant_type=password&client_id=client1&client_secret=client1&username=user1&password=user1&scope=read,write,trust"

如果我在没有范围的情况下尝试此请求,则会出现以下错误。

"detailMessage":"Bad credentials","cause":{"detailMessage":"Bad credentials"

下面是我的spring security配置文件。

spring-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:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd ">

      <http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
            xmlns="http://www.springframework.org/schema/security">
          <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
          <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"/>
      </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="/protected/**" 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="/protected/**" access="ROLE_USER"/>
          <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
          <access-denied-handler ref="oauthAccessDeniedHandler"/>
      </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"/>
              </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.InMemoryTokenStore">
  <!--         <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="accessTokenValiditySeconds" value="3600" />
      <property name="refreshTokenValiditySeconds" value="5270400"></property>
          <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="com.example.myproject.ser.ClientService">
      </bean>

      <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>

ClientService.java:

      import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.security.oauth2.provider.ClientDetails;
  import org.springframework.security.oauth2.provider.ClientDetailsService;
  import org.springframework.security.oauth2.provider.ClientRegistrationException;
  import org.springframework.security.oauth2.provider.client.BaseClientDetails;
  import org.springframework.stereotype.Component;

  import com.example.myproject.rep.OauthRepository;

  @Component
  public class ClientService implements ClientDetailsService {

      @Autowired
      private OauthRepository oauthRepository;

      @Override
      public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException {
          BaseClientDetails clientDetails = oauthRepository.getByClientId(s);
          return clientDetails;
      }
  }

OauthRepository.java:

      @Repository
  @Transactional
  public class OauthRepository {

    @Autowired
    private SessionFactory sessionFactory;

    private org.hibernate.Session getCurrentSession(){
      return sessionFactory.getCurrentSession();
    }



      public BaseClientDetails getByClientId(String clientId) {
        Query query=getCurrentSession().createQuery("FROM OauthClientDetails WHERE clientId=:clientId");
        query.setParameter("clientId", clientId);
        List<OauthClientDetails> getClient=query.list();

        OauthClientDetails oauthClient=getClient.get(0);
        BaseClientDetails details = new BaseClientDetails(oauthClient.getClientId(),oauthClient.getResourceIds(),oauthClient.getScope(),oauthClient.getAuthorizedGrantTypes(),oauthClient.getAuthorities());
        details.setClientSecret(oauthClient.getClientSecret());

          return details;



      }
       } 

下面是我的数据库客户端表数据。

         CREATE TABLE oauth_client_details (
      client_id varchar(50) 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 ('client1', 'rest_api', 'client1', 'read,write,trust', 'password,authorization_code,refresh_token,implicit', 'ROLE_ANDROID', '5', '1000');

请帮我解决问题

【问题讨论】:

  • 根据 RFC 6749 (tools.ietf.org/html/rfc6749#section-3.3) “范围参数的值表示为空格分隔、区分大小写的字符串列表。”您的请求参数看起来是用逗号分隔的:“&scope=read,write,trust”
  • @Jim.R 那我应该在那里写什么呢?
  • 这应该可以工作 - curl -X POST localhost:8080/MyProjectOauth/oauth/token -H “Accept: application/json” -d "grant_type=password&client_id=client1&client_secret=client1&username=user1&password=user1&scope=读写信任"

标签: access-token spring-security-oauth2 oauth2


【解决方案1】:

范围参数应该用空格分隔。

这应该可以工作 - curl -X POST localhost:8080/MyProjectOauth/oauth/token -H “Accept: application/json” -d "grant_type=password&client_id=client1&client_secret=client1‌​&username=user1&pass‌​word=user1&scope=rea‌​ d 写信任”

Jim R 在上面的 cmets 中回答了这个问题。我只是把它移到一个答案上,这样会更容易找到。

【讨论】:

    猜你喜欢
    • 2020-10-05
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 2016-04-24
    • 2016-06-22
    • 2011-10-25
    • 2019-03-13
    • 2015-03-30
    相关资源
    最近更新 更多