Bootstrap

spring security oauth2之refresh token

oAuth2.0认证服务器生成的Access_token是有有效期限制的默认为12个小时,refresh_token默认为三十天。如果Access_token提示过期,可以根据refresh_token获取新的Access_token

下面介绍如何生成refresh_token,并根据refresh_token获取新的Access_token:

authorizedGrantTypes

oauth2官方只有4种授权方式,不过spring security oauth2把refresh token也归为authorizedGrantTypes的一种,因此配置的时候只需要这样就把所有方式都支持了。

如果客户端信息是基于内存存储的则配置方式如下:

@Configuration
@EnableAuthorizationServer //提供/oauth/authorize,/oauth/token,/oauth/check_token,/oauth/confirm_access,/oauth/error
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("demoApp")
                .secret("demoAppSecret")
                .redirectUris("http://localhost:8081/callback") //新增redirect_uri
                .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token",
                        "password", "implicit")
                .scopes("all")
                .resourceIds("oauth2-resource")
                .accessTokenValiditySeconds(120)
                .refreshTokenValiditySeconds(60);
    }
}

客户信息如果基于JDBC数据库存储则配置信息如下:

package com.funtl.oauth2.server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import com.funtl.oauth2.server.config.service.UserDetailsServiceImpl;

import javax.sql.DataSource;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
  
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")  
    public DataSource dataSource() {
        // 配置数据源(注意,我使用的是 HikariCP 连接池),以上注解是指定数据源,否则会有冲突
        return DataSourceBuilder.create().build();
    }

   
    
    @Bean
    public TokenStore tokenStore() {
        // 基于 JDBC 实现,令牌保存到数据
        return new JdbcTokenStore(dataSource());
    }

    @Bean  
    public ClientDetailsService jdbcClientDetails() {
        // 基于 JDBC 实现,需要事先在数据库配置客户端信息  
        return new JdbcClientDetailsService(dataSource());
    }

    @Bean
    public UserDetailsService userDetailsService1() {  
    	WebSecurityConfiguration webSecurity = new WebSecurityConfiguration();
        return webSecurity.userDetailsService();
    }
    
    @Override  
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    	
        // 设置令牌        
        endpoints.tokenStore(tokenStore()).userDetailsService(userDetailsService1());  
        // 最后一个参数为替换之后授权页面的url
        endpoints.pathMapping("/oauth/confirm_access","/custom/confirm_access");
            
    }
    
    @Override  
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")  
                .allowFormAuthenticationForClients();
        
        
    }

    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 读取客户端配置
        clients.withClientDetails(jdbcClientDetails());
    }
    
}

数据库客户端详细信息表oauth_client_details维护如下信息:

 

 第二步:配置userDetailsService

要使用refresh_token的话,需要额外配置userDetailsService

配置如下:

 @Bean
    public UserDetailsService userDetailsService1() {  
    	WebSecurityConfiguration webSecurity = new WebSecurityConfiguration();
        return webSecurity.userDetailsService();
    }
    
    @Override  
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    	
        // 设置令牌        
        endpoints.tokenStore(tokenStore()).userDetailsService(userDetailsService1());  
        // 最后一个参数为替换之后授权页面的url
        endpoints.pathMapping("/oauth/confirm_access","/custom/confirm_access");
           
    }

否则则会提示如下报错信息:

HTTP/1.1 500
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
X-Application-Context: application
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Dec 2017 13:35:33 GMT
Connection: close

{"error":"server_error","error_description":"UserDetailsService is required."}

具体的接口调用请参照如下博客:

Spring Security oAuth2.0之refresh_token

最近准备了一个公众号每天都会推送一些开发中经常遇到的问题解决方法,希望多久关注一下,谢谢支持:

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;