import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; import org.springframework.security.oauth2.client.OAuth2ClientContext; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException; import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; import org.springframework.security.oauth2.client.token.AccessTokenRequest; import org.springframework.security.oauth2.client.token.RequestEnhancer; import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider; import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; import org.springframework.security.oauth2.common.AuthenticationScheme; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.stereotype.Controller; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @Controller public class LoginController { @Autowired private OAuth2ClientContext context; @Bean @Scope("session") public OAuth2ClientContext createContext() { return new DefaultOAuth2ClientContext(); } @ResponseBody @RequestMapping("/weixin/authorize") public Object getUserInfo(HttpServletRequest request) { class WeixinAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider { public WeixinAuthorizationCodeAccessTokenProvider(List<HttpMessageConverter<?>> messageConverters) { this.setMessageConverters(messageConverters); this.setTokenRequestEnhancer(new RequestEnhancer() { @Override public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form, HttpHeaders headers) { String clientId = form.getFirst("client_id"); String clientSecret = form.getFirst("client_secret"); form.set("appid", clientId); form.set("secret", clientSecret); form.remove("client_id"); form.remove("client_secret"); } }); } @Override public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException { try { return super.obtainAccessToken(details, request); } catch (UserRedirectRequiredException e) { Map<String, String> params = e.getRequestParams(); String clientId = params.get("client_id"); params.put("appid", clientId); params.remove("client_id"); throw e; } } } class WeixinOAuth2RestTemplate extends OAuth2RestTemplate { public WeixinOAuth2RestTemplate(AuthorizationCodeResourceDetails resource, OAuth2ClientContext context) { super(resource, context); List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); messageConverters.add(new MappingJackson2HttpMessageConverter() { @Override protected boolean canRead(MediaType mediaType) { return true; } }); this.setMessageConverters(messageConverters); this.setAccessTokenProvider(new WeixinAuthorizationCodeAccessTokenProvider(messageConverters)); } @Override protected URI appendQueryParameter(URI uri, OAuth2AccessToken accessToken) { uri = super.appendQueryParameter(uri, accessToken); String url = uri.toString(); if (url.contains("$openid$")) { String openid = (String) accessToken.getAdditionalInformation().get("openid"); try { uri = new URI(url.replace("$openid$", openid)); } catch (URISyntaxException e) { e.printStackTrace(); } } return uri; } } AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails(); resource.setAuthenticationScheme(AuthenticationScheme.form); resource.setClientAuthenticationScheme(AuthenticationScheme.form); resource.setClientId("xxxxxxxxxxx"); resource.setClientSecret("xxxxxxxxxxx"); resource.setUserAuthorizationUri("https://open.weixin.qq.com/connect/oauth2/authorize"); resource.setAccessTokenUri("https://api.weixin.qq.com/sns/oauth2/access_token"); resource.setScope(Arrays.asList("snsapi_userinfo")); context.getAccessTokenRequest().setCurrentUri(request.getRequestURL().toString()); // resource.setPreEstablishedRedirectUri("http://www.baidu.com"); // resource.setUseCurrentUri(false); OAuth2RestTemplate template = new WeixinOAuth2RestTemplate(resource, context); String url = "https://api.weixin.qq.com/sns/userinfo?lang=zh_CN&openid=$openid$"; ResponseEntity<Object> result = template.getForEntity(url, Object.class); return result.getBody(); } }
https://www.cnblogs.com/kingsy/p/6375881.html
class WeixinClientCredentialsAccessTokenProvider extends ClientCredentialsAccessTokenProvider { public WeixinClientCredentialsAccessTokenProvider() { List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>(); converters.add(new MappingJackson2HttpMessageConverter()); this.setMessageConverters(converters); this.setTokenRequestEnhancer(new RequestEnhancer() { @Override public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form, HttpHeaders headers) { form.set("appid", resource.getClientId()); form.set("secret", resource.getClientSecret()); form.set("grant_type", "client_credential"); } }); }
OAuth2ClientContext context = new DefaultOAuth2ClientContext(); ClientCredentialsResourceDetails resource = new ClientCredentialsResourceDetails(); resource.setClientId("xxxxxxxxx"); resource.setClientSecret("xxxxxxxxxxxxxxx"); resource.setAccessTokenUri("https://api.weixin.qq.com/cgi-bin/token"); resource.setAuthenticationScheme(AuthenticationScheme.form); OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource, context); restTemplate.setAccessTokenProvider(new WeixinClientCredentialsAccessTokenProvider()); restTemplate.setRetryBadAccessTokens(true); ResponseEntity<Object> response = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/user/get", Object.class); if (response.getStatusCode() == HttpStatus.OK) { System.out.println(response.getBody()); }
http://www.cnblogs.com/kingsy/p/6375880.htmlhtml
使用背景 :公司有個開放平臺,若要訪問開放平臺,必須先要獲取受權訪問令牌(也就是下面說的:access_token)。公司的受權系統是用spring oauth2.0實現的,今天就不講這個項目,網上比較多。今天主要是講下如何用spring OAuth2.0 Client 組件會去實現高效獲取access_token。
如下是實現代碼:java
1.項目啓動後,從oauth.properties獲取相關的信息(如公鑰、私鑰等信息),而後實例化OAuth2RestTemplate,主要是經過OAuth2RestTemplate這個類去獲取access_tokenweb
@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,這裏我只能本身手動清除。spring
@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.如下配置是受權服務給配置的json
#==================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.htmlapi