如何使刷新令牌有效期长并且每次在spring security oauth2中出现新的refresh_token grant_type时都会发出新的刷新令牌

时间:2016-07-27 04:45:31

标签: spring authentication oauth-2.0 spring-security-oauth2

我正在使用spring security oauth2对我的Android应用程序客户端进行身份验证。当客户端请求带有grant_type作为密码时,服务器会发出访问令牌并刷新令牌。如果访问令牌过期,我可以通过发送发出新的访问令牌请求grant_type为refresh_token.Now如果我的刷新令牌到期我该怎么办?我不想提示用户使用他的凭证再次进行身份验证。那么有没有办法发布新的刷新令牌和新的访问令牌?或者是否有任何规定来发出具有无限有效性的刷新令牌,或者只发送一次刷新令牌并刷新每个refresh_token grant_type请求中的刷新令牌。下面是我的spring security oauth2的配置文件。

      <?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:context="http://www.springframework.org/schema/context"
    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-1.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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd ">


    <!-- This is default url to get a token from OAuth -->
    <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>
    <!-- This is where we tells spring security what URL should be protected 
      and what roles have access to them -->
    <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_APP" />
      <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>
    <authentication-manager alias="authenticationManager"
      xmlns="http://www.springframework.org/schema/security">
      <authentication-provider  user-service-ref="userService">
      </authentication-provider>
    </authentication-manager>

    <bean id="userService"
      class="com.example.myproject.ser.UserService">
    </bean>

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


    <!-- This defined token store, we have used inmemory tokenstore for now 
      but this can be changed to a user defined one -->
    <bean id="tokenStore"
      class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

    <!-- This is where we defined token based configurations, token validity 
      and other things -->
    <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="120" />  <!-- 2 hour 3600 -->
      <property name="refreshTokenValiditySeconds" value="420"></property>   <!-- 2 month 5270400 -->
      <property name="clientDetailsService" ref="clientDetails" />
    </bean>

    <bean id="userApprovalHandler"
      class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
      <property name="tokenServices" ref="tokenServices" />
    </bean>
    <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>

在我的Android应用程序中,我有从多个设备验证同一用户的规定。如果已经在其他设备中验证了,则可以在任何设备中进行身份验证。因此解决方案不会影响这种情况。

2 个答案:

答案 0 :(得分:5)

您可以在客户端级别设置刷新令牌的有效期(请参阅org.springframework.security.oauth2.provider.ClientDetails和org.springframework.security.oauth2.provider.ClientDetailsS​​ervice)。 您需要在客户端详细信息服务加载的客户端上设置此项。

public classs MyClientDetailsService implements ClientDetailsService {
    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        BaseClientDetails client = new BaseClientDetails();
        client.setRefreshTokenValiditySeconds(Integer.MAX_VALUE);
        ...
        return client;
    }
}

或者,您可以在授权服务器配置中的org.springframework.security.oauth2.provider.token.DefaultTokenServices(假设这是您在服务器中使用的实现)上设置默认有效性。您可以通过将以下方法添加到授权服务器配置类来执行此操作。

@Bean
public AuthorizationServerTokenServices authorizationServerTokenServices() throws Exception {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetailsService);
        tokenServices.setRefreshTokenValiditySeconds(Integer.MAX_VALUE);
        return tokenServices;
}

虽然该刷新令牌已经过期,但我认为获得新令牌的唯一方法是让用户重新进行身份验证。

答案 1 :(得分:0)

根据spring-security-oauthDefaultTokenServices的源代码传递一个小于或等于零的值,因为刷新令牌的有效性应足以使其永久持续。请查看here

然后授权服务器配置中的代码应如下所示:

@Bean    
fun tokenServices(): DefaultTokenServices {
    val defaultTokenServices = DefaultTokenServices()
    defaultTokenServices.setTokenStore(tokenStore())
    defaultTokenServices.setRefreshTokenValiditySeconds(0)

    return defaultTokenServices
}

或者,如果您有JdbcClientDetailsService,则可以在oauth_client_details表格中设置刷新令牌到期日期。