客户端通过授权码模式获取不透明令牌(opaque token),使用令牌访问资源服务器
资源服务器安全配置只能处理客户端scope授权,如果添加用户授权的判定规则,则报错
原因www-authenticate: Bearer error=“insufficient_scope”,error_description=“The request requires higher privileges than provided by the access token.”,error_uri=“https://tools.ietf.org/html/rfc6750#section-3.1”
spring security 5 默认的令牌校验逻辑只处理scope,没有处理用户授权
源码- 资源服务器不透明令牌默认配置
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerOpaqueTokenConfiguration
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(OpaqueTokenIntrospector.class) static class OpaqueTokenIntrospectionClientConfiguration { @Bean @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.opaquetoken.introspection-uri") NimbusOpaqueTokenIntrospector opaqueTokenIntrospector(OAuth2ResourceServerProperties properties) { OAuth2ResourceServerProperties.Opaquetoken opaqueToken = properties.getOpaquetoken(); return new NimbusOpaqueTokenIntrospector(opaqueToken.getIntrospectionUri(), opaqueToken.getClientId(), opaqueToken.getClientSecret()); } }
- 内省和验证不透明令牌
org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector
private OAuth2AuthenticatedPrincipal convertClaimsSet(TokenIntrospectionSuccessResponse response) { Collection解决authorities = new ArrayList<>(); Map claims = response.toJSONObject(); ... // 处理scope授权,加上前缀"SCOPE_" if (response.getScope() != null) { List scopes = Collections.unmodifiableList(response.getScope().toStringList()); claims.put(OAuth2IntrospectionClaimNames.SCOPE, scopes); for (String scope : scopes) { authorities.add(new SimpleGrantedAuthority(this.authorityPrefix + scope)); } } // 授权中只包含scope,用户授权直接作为一般属性传递了 return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities); }
- 自定义内省器
import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.util.JSONUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; import org.springframework.web.client.RestOperations; import java.util.ArrayList; import java.util.Collection; import java.util.List; @Slf4j public class DefaultOpaqueTokenIntrospector extends NimbusOpaqueTokenIntrospector { public DefaultOpaqueTokenIntrospector(String introspectionUri, String clientId, String clientSecret) { super(introspectionUri, clientId, clientSecret); } public DefaultOpaqueTokenIntrospector(String introspectionUri, RestOperations restOperations) { super(introspectionUri, restOperations); } @Override public OAuth2AuthenticatedPrincipal introspect(String token) { OAuth2AuthenticatedPrincipal principal = super.introspect(token); try { ListuserAuthorities = JSONUtils.to(principal.getAttribute("authorities"), List.class); Collection authorities = new ArrayList<>(); authorities.addAll(principal.getAuthorities()); for (String userAuthority : userAuthorities) { authorities.add(new SimpleGrantedAuthority(userAuthority)); } return new OAuth2IntrospectionAuthenticatedPrincipal(principal.getAttributes(), authorities); } catch (ParseException e) { log.warn("令牌用户授权信息解析失败", e); } return principal; } }
- 配置
@Bean @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.opaquetoken.introspection-uri") NimbusOpaqueTokenIntrospector opaqueTokenIntrospector(OAuth2ResourceServerProperties properties) { OAuth2ResourceServerProperties.Opaquetoken opaqueToken = properties.getOpaquetoken(); return new DefaultOpaqueTokenIntrospector(opaqueToken.getIntrospectionUri(), opaqueToken.getClientId(), opaqueToken.getClientSecret()); } ```
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)