2025年Spring Security OAuth2之scopes配置详解

Spring Security OAuth2之scopes配置详解1 先看下官方文档的说明 地址 https projects spring io spring security oauth docs oauth2 html scope The scope to which the client is limited If scope is undefined or empty the default the client is

大家好,我是讯享网,很高兴认识大家。
1.先看下官方文档的说明
  • 地址:https://projects.spring.io/spring-security-oauth/docs/oauth2.html
  • scope: The scope to which the client is limited. If scope is undefined or empty (the default) the client is not limited by scope.
  • 用来限制客户端的访问范围,如果为空(默认)的话,那么客户端拥有全部的访问范围
    scope中文翻译就是作用域,用来限制客户端权限访问的范围,可以用来设置角色或者权限,也可以不设置。

资料信息:https://stackoverflow.com/questions//spring-oauth-authorization-server-requires-scope


讯享网

2.scopes的校验是在TokenEndpoint进行的
 @RequestMapping( value = {"/oauth/token"}, method = {RequestMethod.POST} ) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { if (!(principal instanceof Authentication)) { throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter."); } else { String clientId = this.getClientId(principal); ClientDetails authenticatedClient = this.getClientDetailsService().loadClientByClientId(clientId); //OAuth2RequestFactory接口的实现类DefaultOAuth2RequestFactory创建token请求对象 TokenRequest tokenRequest = this.getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); if (clientId != null && !clientId.equals("") && !clientId.equals(tokenRequest.getClientId())) { throw new InvalidClientException("Given client ID does not match authenticated client"); } else { //校验scope客户端和服务器端的设置是否匹配 if (authenticatedClient != null) { this.oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient); } if (!StringUtils.hasText(tokenRequest.getGrantType())) { throw new InvalidRequestException("Missing grant type"); } else if (tokenRequest.getGrantType().equals("implicit")) { throw new InvalidGrantException("Implicit grant type not supported from token endpoint"); } else { if (this.isAuthCodeRequest(parameters) && !tokenRequest.getScope().isEmpty()) { this.logger.debug("Clearing scope of incoming token request"); tokenRequest.setScope(Collections.emptySet()); } if (this.isRefreshTokenRequest(parameters)) { tokenRequest.setScope(OAuth2Utils.parseParameterList((String)parameters.get("scope"))); } OAuth2AccessToken token = this.getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); if (token == null) { throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); } else { return this.getResponse(token); } } } } } 

讯享网
3.进入this.oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);查看处理逻辑

oAuth2RequestValidator对象是DefaultOAuth2RequestValidator的实例,进入看下实现逻辑:

讯享网// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.security.oauth2.provider.request; import java.util.Iterator; import java.util.Set; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.OAuth2RequestValidator; import org.springframework.security.oauth2.provider.TokenRequest; public class DefaultOAuth2RequestValidator implements OAuth2RequestValidator { public DefaultOAuth2RequestValidator() { } public void validateScope(AuthorizationRequest authorizationRequest, ClientDetails client) throws InvalidScopeException { this.validateScope(authorizationRequest.getScope(), client.getScope()); } //校验客户端scope和服务端sope方法 public void validateScope(TokenRequest tokenRequest, ClientDetails client) throws InvalidScopeException { this.validateScope(tokenRequest.getScope(), client.getScope()); } //实际的校验方法 private void validateScope(Set<String> requestScopes, Set<String> clientScopes) { //客户端scope不为空并且scope在服务端scope限制范围之内通过校验 //客户端scope不为空,服务端为空或不设置通过校验 if (clientScopes != null && !clientScopes.isEmpty()) { Iterator var3 = requestScopes.iterator(); while(var3.hasNext()) { String scope = (String)var3.next(); if (!clientScopes.contains(scope)) { throw new InvalidScopeException("Invalid scope: " + scope, clientScopes); } } } //如果客户端的scope为空将会抛出异常,所以客户端不可以为空 if (requestScopes.isEmpty()) { throw new InvalidScopeException("Empty scope (either the client or the user is not allowed the requested scopes)"); } } } 
4.DefaultOAuth2RequestFactory实现类组装token请求及校验scopes
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.security.oauth2.provider.request; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.DefaultSecurityContextAccessor; import org.springframework.security.oauth2.provider.OAuth2Request; import org.springframework.security.oauth2.provider.OAuth2RequestFactory; import org.springframework.security.oauth2.provider.SecurityContextAccessor; import org.springframework.security.oauth2.provider.TokenRequest; public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory { private final ClientDetailsService clientDetailsService; private SecurityContextAccessor securityContextAccessor = new DefaultSecurityContextAccessor(); private boolean checkUserScopes = false; public DefaultOAuth2RequestFactory(ClientDetailsService clientDetailsService) { this.clientDetailsService = clientDetailsService; } public void setSecurityContextAccessor(SecurityContextAccessor securityContextAccessor) { this.securityContextAccessor = securityContextAccessor; } public void setCheckUserScopes(boolean checkUserScopes) { this.checkUserScopes = checkUserScopes; } public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) { String clientId = (String)authorizationParameters.get("client_id"); String state = (String)authorizationParameters.get("state"); String redirectUri = (String)authorizationParameters.get("redirect_uri"); Set<String> responseTypes = OAuth2Utils.parseParameterList((String)authorizationParameters.get("response_type")); Set<String> scopes = this.extractScopes(authorizationParameters, clientId); AuthorizationRequest request = new AuthorizationRequest(authorizationParameters, Collections.emptyMap(), clientId, scopes, (Set)null, (Collection)null, false, state, redirectUri, responseTypes); ClientDetails clientDetails = this.clientDetailsService.loadClientByClientId(clientId); request.setResourceIdsAndAuthoritiesFromClientDetails(clientDetails); return request; } public OAuth2Request createOAuth2Request(AuthorizationRequest request) { return request.createOAuth2Request(); } //创建请求入口类 public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) { String clientId = (String)requestParameters.get("client_id"); if (clientId == null) { clientId = authenticatedClient.getClientId(); } else if (!clientId.equals(authenticatedClient.getClientId())) { throw new InvalidClientException("Given client ID does not match authenticated client"); } String grantType = (String)requestParameters.get("grant_type"); //获取客户端传递或者服务端的scope Set<String> scopes = this.extractScopes(requestParameters, clientId); TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scopes, grantType); return tokenRequest; } public TokenRequest createTokenRequest(AuthorizationRequest authorizationRequest, String grantType) { TokenRequest tokenRequest = new TokenRequest(authorizationRequest.getRequestParameters(), authorizationRequest.getClientId(), authorizationRequest.getScope(), grantType); return tokenRequest; } public OAuth2Request createOAuth2Request(ClientDetails client, TokenRequest tokenRequest) { return tokenRequest.createOAuth2Request(client); } //如果参数中的scope为null,则从服务端配置的scope中取,并且根据this.checkUserScopes的值判断是否校验scopes的有效性 private Set<String> extractScopes(Map<String, String> requestParameters, String clientId) { Set<String> scopes = OAuth2Utils.parseParameterList((String)requestParameters.get("scope")); ClientDetails clientDetails = this.clientDetailsService.loadClientByClientId(clientId); if (scopes == null || scopes.isEmpty()) { scopes = clientDetails.getScope(); } if (this.checkUserScopes) { scopes = this.checkUserScopes(scopes, clientDetails); } return scopes; } private Set<String> checkUserScopes(Set<String> scopes, ClientDetails clientDetails) { if (!this.securityContextAccessor.isUser()) { return scopes; } else { Set<String> result = new LinkedHashSet(); Set<String> authorities = AuthorityUtils.authorityListToSet(this.securityContextAccessor.getAuthorities()); Iterator var5 = scopes.iterator(); while(true) { String scope; do { if (!var5.hasNext()) { return result; } scope = (String)var5.next(); } while(!authorities.contains(scope) && !authorities.contains(scope.toUpperCase()) && !authorities.contains("ROLE_" + scope.toUpperCase())); result.add(scope); } } } } 

GitHub源码:https://github.com/mingyang66/spring-parent/tree/master/spring-security-oauth2-server-redis-service

小讯
上一篇 2025-01-29 09:59
下一篇 2025-01-10 10:03

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/16834.html