添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 8 * https://www.apache.org/licenses/LICENSE-2.0 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.springframework.security.oauth2.client.token; 18 import java.util.Collections; 19 import java.util.List; 21 import org.springframework.security.access.AccessDeniedException; 22 import org.springframework.security.authentication.AnonymousAuthenticationToken; 23 import org.springframework.security.authentication.InsufficientAuthenticationException; 24 import org.springframework.security.core.Authentication; 25 import org.springframework.security.core.context.SecurityContextHolder; 26 import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException; 27 import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 28 import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; 29 import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 30 import org.springframework.security.oauth2.common.OAuth2AccessToken; 31 import org.springframework.security.oauth2.common.OAuth2RefreshToken; 32 import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; 34 /** 35 * A chain of OAuth2 access token providers. This implementation will iterate through its 36 * chain to find the first provider that supports the resource and use it to obtain the 37 * access token. Note that the order of the chain is relevant. 38 * 39 * @author Ryan Heaton 40 * @author Dave Syer 41 */ 42 public class AccessTokenProviderChain extends OAuth2AccessTokenSupport 43 implements AccessTokenProvider { 45 private final List<AccessTokenProvider> chain; 47 private ClientTokenServices clientTokenServices; 49 public AccessTokenProviderChain (List<? extends AccessTokenProvider> chain) { 50 this .chain = chain == null ? Collections.<AccessTokenProvider> emptyList() 51 : Collections.unmodifiableList(chain); 54 /** 55 * Token services for long-term persistence of access tokens. 56 * 57 * @param clientTokenServices the clientTokenServices to set 58 */ 59 public void setClientTokenServices( ClientTokenServices clientTokenServices) { 60 this .clientTokenServices = clientTokenServices; 63 public boolean supportsResource( OAuth2ProtectedResourceDetails resource) { 64 for ( AccessTokenProvider tokenProvider : chain) { 65 if (tokenProvider.supportsResource(resource)) { 66 return true ; 69 return false; 72 public boolean supportsRefresh( OAuth2ProtectedResourceDetails resource) { 73 for ( AccessTokenProvider tokenProvider : chain) { 74 if (tokenProvider.supportsRefresh(resource)) { 75 return true ; 78 return false; 81 public OAuth2AccessToken obtainAccessToken( OAuth2ProtectedResourceDetails resource, 82 AccessTokenRequest request) 83 throws UserRedirectRequiredException, AccessDeniedException { 85 OAuth2AccessToken accessToken = null ; 86 OAuth2AccessToken existingToken = null ; 87 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 89 if (auth instanceof AnonymousAuthenticationToken) { 90 if (!resource.isClientOnly()) { 91 throw new InsufficientAuthenticationException( 92 "Authentication is required to obtain an access token (anonymous not allowed)" ); 96 if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) { 97 existingToken = request.getExistingToken(); 98 if (existingToken == null && clientTokenServices != null ) { 99 existingToken = clientTokenServices.getAccessToken(resource, auth); 100 } 102 if (existingToken != null ) { 103 if (existingToken.isExpired()) { 104 if (clientTokenServices != null ) { 105 clientTokenServices.removeAccessToken(resource, auth); 106 } 107 OAuth2RefreshToken refreshToken = existingToken.getRefreshToken(); 108 if (refreshToken != null && !resource.isClientOnly()) { 109 accessToken = refreshAccessToken(resource, refreshToken, request); 110 } 111 } 112 else { 113 accessToken = existingToken; 114 } 115 } 116 } 117 // Give unauthenticated users a chance to get a token and be redirected 119 if (accessToken == null ) { 120 // looks like we need to try to obtain a new token. 121 accessToken = obtainNewAccessTokenInternal(resource, request); 123 if (accessToken == null ) { 124 throw new IllegalStateException( 125 "An OAuth 2 access token must be obtained or an exception thrown." ); 126 } 127 } 129 if (clientTokenServices != null 130 && (resource.isClientOnly() || auth != null && auth.isAuthenticated())) { 131 clientTokenServices.saveAccessToken(resource, auth, accessToken); 132 } 134 return accessToken; 135 } 137 protected OAuth2AccessToken obtainNewAccessTokenInternal( 138 OAuth2ProtectedResourceDetails details, AccessTokenRequest request) 139 throws UserRedirectRequiredException, AccessDeniedException { 141 if (request.isError()) { 142 // there was an oauth error... 143 throw OAuth2Exception.valueOf(request.toSingleValueMap()); 144 } 146 for ( AccessTokenProvider tokenProvider : chain) { 147 if (tokenProvider.supportsResource(details)) { 148 return tokenProvider.obtainAccessToken(details, request); 149 } 150 } 152 throw new OAuth2AccessDeniedException ( 153 "Unable to obtain a new access token for resource '" + details.getId() 154 + "'. The provider manager is not configured to support it." , 155 details); 156 } 158 /** 159 * Obtain a new access token for the specified resource using the refresh token. 160 * 161 * @param resource The resource. 162 * @param refreshToken The refresh token. 163 * @return The access token, or null if failed. 164 * @throws UserRedirectRequiredException 165 */ 166 public OAuth2AccessToken refreshAccessToken( OAuth2ProtectedResourceDetails resource, 167 OAuth2RefreshToken refreshToken, AccessTokenRequest request) 168 throws UserRedirectRequiredException { 169 for ( AccessTokenProvider tokenProvider : chain) { 170 if (tokenProvider.supportsRefresh(resource)) { 171 DefaultOAuth2AccessToken refreshedAccessToken = new DefaultOAuth2AccessToken ( 172 tokenProvider.refreshAccessToken(resource, refreshToken, 173 request)); 174 if (refreshedAccessToken.getRefreshToken() == null ) { 175 // Fixes gh-712 176 refreshedAccessToken.setRefreshToken(refreshToken); 177 } 178 return refreshedAccessToken; 179 } 180 } 181 throw new OAuth2AccessDeniedException ( 182 "Unable to obtain a new access token for resource '" + resource.getId() 183 + "'. The provider manager is not configured to support it." , 184 resource); 185 }