package com.luotuo.config; import org.springframework.http.*; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.oauth2.client.filter.state.DefaultStateKeyGenerator; import org.springframework.security.oauth2.client.filter.state.StateKeyGenerator; 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.*; import org.springframework.security.oauth2.client.token.auth.ClientAuthenticationHandler; import org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler; import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.common.exceptions.InvalidRequestException; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseExtractor; import org.springframework.web.client.RestClientException; import java.io.IOException; import java.net.URI; import java.util.*; /** * Created by luotuo on 17-9-27. */ public class MyAuthorizationCodeAccessTokenProvider extends OAuth2AccessTokenSupport implements AccessTokenProvider { private StateKeyGenerator stateKeyGenerator = new DefaultStateKeyGenerator(); private String scopePrefix = "scope."; private RequestEnhancer authorizationRequestEnhancer = new DefaultRequestEnhancer(); private boolean stateMandatory = true; MappingJackson2HttpMessageConverter customJsonMessageConverter = new MappingJackson2HttpMessageConverter(); public MyAuthorizationCodeAccessTokenProvider() { customJsonMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN)); this.setMessageConverters(Arrays.asList(customJsonMessageConverter)); } public void setStateMandatory(boolean stateMandatory) { this.stateMandatory = stateMandatory; } public void setAuthorizationRequestEnhancer(RequestEnhancer authorizationRequestEnhancer) { this.authorizationRequestEnhancer = authorizationRequestEnhancer; } public void setScopePrefix(String scopePrefix) { this.scopePrefix = scopePrefix; } public void setStateKeyGenerator(StateKeyGenerator stateKeyGenerator) { this.stateKeyGenerator = stateKeyGenerator; } public boolean supportsResource(OAuth2ProtectedResourceDetails resource) { return resource instanceof AuthorizationCodeResourceDetails && "authorization_code".equals(resource.getGrantType()); } public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource) { return this.supportsResource(resource); } public String obtainAuthorizationCode(OAuth2ProtectedResourceDetails details, final AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException { AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails)details; HttpHeaders headers = this.getHeadersForAuthorizationRequest(request); MultiValueMap<String, String> form = new LinkedMultiValueMap(); if(request.containsKey("user_oauth_approval")) { form.set("user_oauth_approval", request.getFirst("user_oauth_approval")); Iterator var6 = details.getScope().iterator(); while(var6.hasNext()) { String scope = (String)var6.next(); form.set(this.scopePrefix + scope, request.getFirst("user_oauth_approval")); } } else { form.putAll(this.getParametersForAuthorizeRequest(resource, request)); } this.authorizationRequestEnhancer.enhance(request, resource, form, headers); final ResponseExtractor<ResponseEntity<Void>> delegate = this.getAuthorizationResponseExtractor(); ResponseExtractor<ResponseEntity<Void>> extractor = new ResponseExtractor<ResponseEntity<Void>>() { public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException { if(response.getHeaders().containsKey("Set-Cookie")) { request.setCookie(response.getHeaders().getFirst("Set-Cookie")); } return (ResponseEntity)delegate.extractData(response); } }; ResponseEntity<Void> response = (ResponseEntity)this.getRestTemplate().execute(resource.getUserAuthorizationUri(), HttpMethod.POST, this.getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()); if(response.getStatusCode() == HttpStatus.OK) { throw this.getUserApprovalSignal(resource, request); } else { URI location = response.getHeaders().getLocation(); String query = location.getQuery(); Map<String, String> map = OAuth2Utils.extractMap(query); String redirectUri; if(map.containsKey("state")) { request.setStateKey((String)map.get("state")); if(request.getPreservedState() == null) { redirectUri = resource.getRedirectUri(request); if(redirectUri != null) { request.setPreservedState(redirectUri); } else { request.setPreservedState(new Object()); } } } redirectUri = (String)map.get("code"); if(redirectUri == null) { throw new UserRedirectRequiredException(location.toString(), form.toSingleValueMap()); } else { request.set("code", redirectUri); return redirectUri; } } } protected ResponseExtractor<ResponseEntity<Void>> getAuthorizationResponseExtractor() { return new ResponseExtractor<ResponseEntity<Void>>() { public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException { return new ResponseEntity(response.getHeaders(), response.getStatusCode()); } }; } public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException { AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails)details; System.out.println(request.getCurrentUri()); if(request.getAuthorizationCode() == null) { if(request.getStateKey() == null) { throw this.getRedirectForAuthorization(resource, request); } this.obtainAuthorizationCode(resource, request); } System.out.println("code == " + request.getAuthorizationCode()); return this.retrieveToken(request, resource, this.getParametersForTokenRequest(resource, request), this.getHeadersForTokenRequest(request)); } public OAuth2AccessToken refreshAccessToken(OAuth2ProtectedResourceDetails resource, OAuth2RefreshToken refreshToken, AccessTokenRequest request) throws UserRedirectRequiredException, OAuth2AccessDeniedException { MultiValueMap<String, String> form = new LinkedMultiValueMap(); form.add("grant_type", "refresh_token"); form.add("refresh_token", refreshToken.getValue()); form.add("appid", resource.getClientId()); try { return this.retrieveToken(request, resource, form, this.getHeadersForTokenRequest(request)); } catch (OAuth2AccessDeniedException var6) { throw this.getRedirectForAuthorization((AuthorizationCodeResourceDetails)resource, request); } } private ClientAuthenticationHandler authenticationHandler = new DefaultClientAuthenticationHandler(); private RequestEnhancer tokenRequestEnhancer = new DefaultRequestEnhancer(); protected OAuth2AccessToken retrieveToken(final AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form, HttpHeaders headers) throws OAuth2AccessDeniedException { try { this.authenticationHandler.authenticateTokenRequest(resource, form, headers); this.tokenRequestEnhancer.enhance(request, resource, form, headers); final ResponseExtractor<OAuth2AccessToken> delegate = this.getResponseExtractor(); ResponseExtractor<OAuth2AccessToken> extractor = new ResponseExtractor<OAuth2AccessToken>() { public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException { if(response.getHeaders().containsKey("Set-Cookie")) { request.setCookie(response.getHeaders().getFirst("Set-Cookie")); } return (OAuth2AccessToken)delegate.extractData(response); } }; System.out.println("URI == " + this.getAccessTokenUri(resource, form)); return (OAuth2AccessToken)this.getRestTemplate().execute(this.getAccessTokenUri(resource, form), this.getHttpMethod(), this.getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()); } catch (OAuth2Exception var8) { System.out.println(var8.toString()); throw new OAuth2AccessDeniedException("Access token denied.", resource, var8); } catch (RestClientException var9) { System.out.println(var9.toString()); throw new OAuth2AccessDeniedException("Error requesting access token.", resource, var9); } } protected HttpMethod getHttpMethod() { return HttpMethod.GET; } protected String getAccessTokenUri(OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) { String accessTokenUri = resource.getAccessTokenUri(); if (form.containsKey("refresh_token")) accessTokenUri = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; if(this.logger.isDebugEnabled()) { this.logger.debug("Retrieving token from " + accessTokenUri); } StringBuilder builder = new StringBuilder(accessTokenUri); if(this.getHttpMethod() == HttpMethod.GET) { String separator = "?"; if(accessTokenUri.contains("?")) { separator = "&"; } for(Iterator var6 = form.keySet().iterator(); var6.hasNext(); separator = "&") { String key = (String)var6.next(); builder.append(separator); builder.append(key + "={" + key + "}"); } } if (form.containsKey("refresh_token")) return builder.toString(); return builder.toString() + "#wechat_redirect"; } private HttpHeaders getHeadersForTokenRequest(AccessTokenRequest request) { HttpHeaders headers = new HttpHeaders(); return headers; } private HttpHeaders getHeadersForAuthorizationRequest(AccessTokenRequest request) { HttpHeaders headers = new HttpHeaders(); headers.putAll(request.getHeaders()); if(request.getCookie() != null) { headers.set("Cookie", request.getCookie()); } return headers; } private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) { MultiValueMap<String, String> form = new LinkedMultiValueMap(); String state = request.getStateKey(); // if (state.contains("session")) { // form.set("appid", resource.getClientId()); // form.set("secret", resource.getClientSecret()); // } else { // form.set("appid", "wx38871ac04c8208af"); // form.set("secret", "50f7e835165d91006bf32fb3ba8d53dd"); // } form.set("appid", resource.getClientId()); form.set("secret", resource.getClientSecret()); form.set("code", request.getAuthorizationCode()); form.set("grant_type", "authorization_code"); Object preservedState = request.getPreservedState(); //if((request.getStateKey() != null || this.stateMandatory) && preservedState == null) { if(false) { throw new InvalidRequestException("Possible CSRF detected - state parameter was required but no state could be found"); } else { String redirectUri = null; if(preservedState instanceof String) { redirectUri = String.valueOf(preservedState); } else { redirectUri = resource.getRedirectUri(request); } if(redirectUri != null && !"NONE".equals(redirectUri)) { form.set("redirect_uri", redirectUri); } return form; } } private MultiValueMap<String, String> getParametersForAuthorizeRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) { MultiValueMap<String, String> form = new LinkedMultiValueMap(); form.set("response_type", "code"); form.set("client_id", resource.getClientId()); if(request.get("scope") != null) { form.set("scope", request.getFirst("scope")); } else { form.set("scope", OAuth2Utils.formatParameterList(resource.getScope())); } String redirectUri = resource.getPreEstablishedRedirectUri(); Object preservedState = request.getPreservedState(); if(redirectUri == null && preservedState != null) { redirectUri = String.valueOf(preservedState); } else { redirectUri = request.getCurrentUri(); } String stateKey = request.getStateKey(); if(stateKey != null) { form.set("state", stateKey); if(preservedState == null) { throw new InvalidRequestException("Possible CSRF detected - state parameter was present but no state could be found"); } } if(redirectUri != null) { form.set("redirect_uri", redirectUri); } return form; } private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) { TreeMap<String, String> requestParameters = new TreeMap(); requestParameters.put("response_type", "code"); requestParameters.put("client_id", resource.getClientId()); String redirectUri = resource.getRedirectUri(request); if(redirectUri != null) { requestParameters.put("redirect_uri", redirectUri); } if(resource.isScoped()) { StringBuilder builder = new StringBuilder(); List<String> scope = resource.getScope(); if(scope != null) { Iterator scopeIt = scope.iterator(); while(scopeIt.hasNext()) { builder.append((String)scopeIt.next()); if(scopeIt.hasNext()) { builder.append(' '); } } } requestParameters.put("scope", builder.toString()); } UserRedirectRequiredException redirectException = new UserRedirectRequiredException(resource.getUserAuthorizationUri(), requestParameters); String stateKey = this.stateKeyGenerator.generateKey(resource); redirectException.setStateKey(stateKey); request.setStateKey(stateKey); redirectException.setStateToPreserve(redirectUri); request.setPreservedState(redirectUri); return redirectException; } protected UserApprovalRequiredException getUserApprovalSignal(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) { String message = String.format("Do you approve the client '%s' to access your resources with scope=%s", new Object[]{resource.getClientId(), resource.getScope()}); return new UserApprovalRequiredException(resource.getUserAuthorizationUri(), Collections.singletonMap("user_oauth_approval", message), resource.getClientId(), resource.getScope()); } }