1. 程式人生 > >如何用Spring OAuth2.0 Client元件獲取授權access_token

如何用Spring OAuth2.0 Client元件獲取授權access_token

使用背景 :公司有個開放平臺,若要訪問開放平臺,必須先要獲取授權訪問令牌(也就是下面說的:access_token)。公司的授權系統是用spring oauth2.0實現的,今天就不講這個專案,網上比較多。今天主要是講下如何用spring OAuth2.0 Client 元件會去實現高效獲取access_token。

以下是實現程式碼:

1.專案啟動後,從oauth.properties獲取相關的資訊(如公鑰、私鑰等資訊),然後例項化OAuth2RestTemplate,主要是通過OAuth2RestTemplate這個類去獲取access_token,.

@EnableOAuth2Client
@Configuration
@Component
public class Oauth2Config{
	
	private final static Logger logger = Logger.getLogger(Oauth2Config.class);
	
	private static String location = "classpath:config/*/oauth.properties";
	
	private static Map<String,String> oauthInfo = new HashMap<String,String>();
	
	@Autowired
	private OAuth2ClientContext oauth2Context;
	
	/**
	 * 獲取配置檔案資訊
	 */
	static{
		ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
		Resource[] resources;
		try {
			resources = patternResolver.getResources(location);
			location = resources[0].getFile().getAbsolutePath();
			logger.info("location" + location);
			Properties props = new Properties();  
	        try {  
	        	if(location.contains("dev")){
	        		props = PropertiesLoaderUtils.loadAllProperties("config/dev/oauth.properties");
	        	}else if(location.contains("test")){
	        		props = PropertiesLoaderUtils.loadAllProperties("config/test/oauth.properties");
	        	}else if(location.contains("production")){
	        		props = PropertiesLoaderUtils.loadAllProperties("config/production/oauth.properties");
	        	}
	            for(Object key:props.keySet()){  
	            	logger.warn(key + " : " +  (String)props.get(key));
	            	oauthInfo.put((String) key, (String)props.get(key));
	            }  
	        } catch (IOException e) {  
	            System.out.println(e.getMessage());  
	        }  
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	} 
	
	
	@Bean
	public AccessTokenRequest accessTokenRequest(){
		AccessTokenRequest defaultAccessTokenRequest = new DefaultAccessTokenRequest();
		Map<String, List<String>> headers = new HashMap<String, List<String>>();
		List<String> headerList=new ArrayList<String>();
		headerList.add("Basic " + oauthInfo.get("public_key"));
        headers.put("Authorization", headerList);
        defaultAccessTokenRequest.setHeaders(headers);
        defaultAccessTokenRequest.setCurrentUri(oauthInfo.get("redirect_uri"));
	    return defaultAccessTokenRequest;
	}
	
	@Bean
	public AuthorizationCodeResourceDetails resourceDetails(){
		AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
		resource.setAccessTokenUri(oauthInfo.get("oauth_url") + oauthInfo.get("request_and_refresh_token"));
		resource.setClientId(oauthInfo.get("client_id"));
        resource.setGrantType("authorization_code");
        resource.setUserAuthorizationUri(oauthInfo.get("oauth_url") + oauthInfo.get("request_code_url"));
        resource.setScope(Arrays.asList("app"));
        resource.setPreEstablishedRedirectUri(oauthInfo.get("redirect_uri"));
	    return resource;
	}
	
	@Bean
	public OAuth2RestTemplate oAuth2RestTemplate(){
        accessTokenRequest().setPreservedState(oauthInfo.get("redirect_uri"));
        accessTokenRequest().setStateKey(new DefaultStateKeyGenerator().generateKey(resourceDetails()));
        
        AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
        provider.setAuthenticationHandler(new ClientAuthenticationHandler() {
			@Override
			public void authenticateTokenRequest(
					OAuth2ProtectedResourceDetails resource,
					MultiValueMap<String, String> form, HttpHeaders headers) {
				headers.set("Authorization", "Basic " + oauthInfo.get("private_key") );
			}
		});
        AccessTokenProviderChain providerChain = new AccessTokenProviderChain(Arrays.asList(provider));
        //oauth2Context.setPreservedState(accessTokenRequest().getStateKey(),accessTokenRequest().getPreservedState());
        OAuth2RestTemplate template=new OAuth2RestTemplate(resourceDetails(),oauth2Context);
        template.setAccessTokenProvider(providerChain);
        return template;
	}

	
}


2.通過OAuth2RestTemplate去獲取access_token的值,之所以每次都情況授權code,是因為spring oauth2授權code只能用一次便廢棄,然後起OAuth2ClientContext類又不主動清空code,這裡我只能自己手動清除。

@Component
public class AccessTokenUtils {

	private final static Logger logger = Logger.getLogger(AccessTokenUtils.class);
	
	
	@Autowired
    private OAuth2RestTemplate restTemplate;
	
	@Autowired
	private Oauth2Config oauth2Config;
	
	
	/**
	 * 獲取oauth2的授權令牌access_token
	 * @return
	 */
	public  String getAccessToken(){
		logger.info("獲取oauth2的授權令牌access_token start ...");
		OAuth2ClientContext oAuth2ClientContext = restTemplate.getOAuth2ClientContext();
		oAuth2ClientContext.getAccessTokenRequest().setAuthorizationCode(null);//清空授權code
		String stateKey = oAuth2ClientContext.getAccessTokenRequest().getStateKey();
		Object preservedState = oAuth2ClientContext.getAccessTokenRequest().getPreservedState();
		if(StringUtils.isEmpty(stateKey))
			stateKey = new DefaultStateKeyGenerator().generateKey(oauth2Config.resourceDetails());
		if(preservedState == null )
			preservedState = VipConstant.redirtUrl;
		
		logger.info("statekey:" + stateKey + " ; preservedState : " + preservedState);
		oAuth2ClientContext.setPreservedState(oAuth2ClientContext.getAccessTokenRequest().getStateKey(), oAuth2ClientContext.getAccessTokenRequest().getPreservedState());
		OAuth2AccessToken oAuth2AccessToken = this.restTemplate.getAccessToken();
		String access_token = oAuth2AccessToken.getValue();
		logger.info("獲取oauth2的授權令牌access_token end ;access_token = " +  access_token + ";失效時間 = " + oAuth2AccessToken.getExpiration() + " ;剩餘失效時間:" + oAuth2AccessToken.getExpiresIn() );
		return access_token;
	}
	
}


3.以下配置是授權服務給配置的
#==================spring oauth2.0=====================================
#客戶端ID
client_id=xxx
#公鑰(BASE64(xx))
public_key=xxx
#私鑰(BASE64(xx))
private_key=xx
#spring oauth2.0服務url
oauth_url=xxx
#獲取請求code URL
request_code_url=oauth/authorize
#獲取請求token或重新整理token URL
request_and_refresh_token=oauth/token
#回撥地址
redirect_uri=http://www.baidu.com

Spring OAuth2.0 Client官網地址:http://projects.spring.io/spring-security-oauth/docs/oauth2.html