spring security oauth2 资源服务器配置及检验过程

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ResourceServerConfiguration.class})
public @interface EnableResourceServer {
}
@Configuration
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter implements Ordered {
    private int order = 3;
    @Autowired(
        required = false
    )
    private TokenStore tokenStore;
    @Autowired(
        required = false
    )
    private AuthenticationEventPublisher eventPublisher;
    @Autowired(
        required = false
    )
    private Map<String, ResourceServerTokenServices> tokenServices;
    @Autowired
    private ApplicationContext context;
    private List<ResourceServerConfigurer> configurers = Collections.emptyList();
    @Autowired(
        required = false
    )
    private AuthorizationServerEndpointsConfiguration endpoints;

    public ResourceServerConfiguration() {
    }

    public int getOrder() {
        return this.order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Autowired(
        required = false
    )
    public void setConfigurers(List<ResourceServerConfigurer> configurers) {
        this.configurers = configurers;
    }

    protected void configure(HttpSecurity http) throws Exception {
        ResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer();
        ResourceServerTokenServices services = this.resolveTokenServices();
        if (services != null) {
            resources.tokenServices(services);
        } else if (this.tokenStore != null) {
            resources.tokenStore(this.tokenStore);
        } else if (this.endpoints != null) {
            resources.tokenStore(this.endpoints.getEndpointsConfigurer().getTokenStore());
        }

        if (this.eventPublisher != null) {
            resources.eventPublisher(this.eventPublisher);
        }

        Iterator i$ = this.configurers.iterator();

        ResourceServerConfigurer configurer;
        while(i$.hasNext()) {
            configurer = (ResourceServerConfigurer)i$.next();
            configurer.configure(resources);
        }

        ((HttpSecurity)((HttpSecurity)http.authenticationProvider(new AnonymousAuthenticationProvider("default")).exceptionHandling().accessDeniedHandler(resources.getAccessDeniedHandler()).and()).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()).csrf().disable();
        http.apply(resources);
        if (this.endpoints != null) {
            http.requestMatcher(new ResourceServerConfiguration.NotOAuthRequestMatcher(this.endpoints.oauth2EndpointHandlerMapping()));
        }

        i$ = this.configurers.iterator();

        while(i$.hasNext()) {
            configurer = (ResourceServerConfigurer)i$.next();
            configurer.configure(http);
        }

        if (this.configurers.isEmpty()) {
            ((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
        }

    }

    private ResourceServerTokenServices resolveTokenServices() {
        if (this.tokenServices != null && this.tokenServices.size() != 0) {
            if (this.tokenServices.size() == 1) {
                return (ResourceServerTokenServices)this.tokenServices.values().iterator().next();
            } else {
                if (this.tokenServices.size() == 2) {
                    Iterator<ResourceServerTokenServices> iter = this.tokenServices.values().iterator();
                    ResourceServerTokenServices one = (ResourceServerTokenServices)iter.next();
                    ResourceServerTokenServices two = (ResourceServerTokenServices)iter.next();
                    if (this.elementsEqual(one, two)) {
                        return one;
                    }
                }

                return (ResourceServerTokenServices)this.context.getBean(ResourceServerTokenServices.class);
            }
        } else {
            return null;
        }
    }

    private boolean elementsEqual(Object one, Object two) {
        if (one == two) {
            return true;
        } else {
            Object targetOne = this.findTarget(one);
            Object targetTwo = this.findTarget(two);
            return targetOne == targetTwo;
        }
    }

    private Object findTarget(Object item) {
        Object current = item;

        while(current instanceof Advised) {
            try {
                current = ((Advised)current).getTargetSource().getTarget();
            } catch (Exception var4) {
                ReflectionUtils.rethrowRuntimeException(var4);
            }
        }

        return current;
    }

    private static class NotOAuthRequestMatcher implements RequestMatcher {
        private FrameworkEndpointHandlerMapping mapping;

        public NotOAuthRequestMatcher(FrameworkEndpointHandlerMapping mapping) {
            this.mapping = mapping;
        }

        public boolean matches(HttpServletRequest request) {
            String requestPath = this.getRequestPath(request);
            Iterator i$ = this.mapping.getPaths().iterator();

            String path;
            do {
                if (!i$.hasNext()) {
                    return true;
                }

                path = (String)i$.next();
            } while(!requestPath.startsWith(this.mapping.getPath(path)));

            return false;
        }

        private String getRequestPath(HttpServletRequest request) {
            String url = request.getServletPath();
            if (request.getPathInfo() != null) {
                url = url + request.getPathInfo();
            }

            return url;
        }
    }
}

package org.springframework.boot.autoconfigure.security.oauth2.resource;

import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer.AuthorizedUrl;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

@Configuration
@Conditional({OAuth2ResourceServerConfiguration.ResourceServerCondition.class})
@ConditionalOnClass({EnableResourceServer.class, SecurityProperties.class})
@ConditionalOnWebApplication
@ConditionalOnBean({ResourceServerConfiguration.class})
@Import({ResourceServerTokenServicesConfiguration.class})
public class OAuth2ResourceServerConfiguration {
    private final ResourceServerProperties resource;

    public OAuth2ResourceServerConfiguration(ResourceServerProperties resource) {
        this.resource = resource;
    }

    @Bean
    @ConditionalOnMissingBean({ResourceServerConfigurer.class})
    public ResourceServerConfigurer resourceServer() {
        return new OAuth2ResourceServerConfiguration.ResourceSecurityConfigurer(this.resource);
    }

    @ConditionalOnBean({AuthorizationServerEndpointsConfiguration.class})
    private static class AuthorizationServerEndpointsConfigurationBeanCondition {
        private AuthorizationServerEndpointsConfigurationBeanCondition() {
        }

        public static boolean matches(ConditionContext context) {
            Class<OAuth2ResourceServerConfiguration.AuthorizationServerEndpointsConfigurationBeanCondition> type = OAuth2ResourceServerConfiguration.AuthorizationServerEndpointsConfigurationBeanCondition.class;
            Conditional conditional = (Conditional)AnnotationUtils.findAnnotation(type, Conditional.class);
            StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(type);
            Class[] var4 = conditional.value();
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Class<? extends Condition> conditionType = var4[var6];
                Condition condition = (Condition)BeanUtils.instantiateClass(conditionType);
                if (condition.matches(context, metadata)) {
                    return true;
                }
            }

            return false;
        }
    }

    protected static class ResourceServerCondition extends SpringBootCondition implements ConfigurationCondition {
        private static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable.mapOf(String.class, Object.class);
        private static final String AUTHORIZATION_ANNOTATION = "org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration";

        protected ResourceServerCondition() {
        }

        public ConfigurationPhase getConfigurationPhase() {
            return ConfigurationPhase.REGISTER_BEAN;
        }

        public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Builder message = ConditionMessage.forCondition("OAuth ResourceServer Condition", new Object[0]);
            Environment environment = context.getEnvironment();
            if (!(environment instanceof ConfigurableEnvironment)) {
                return ConditionOutcome.noMatch(message.didNotFind("A ConfigurableEnvironment").atAll());
            } else if (this.hasOAuthClientId(environment)) {
                return ConditionOutcome.match(message.foundExactly("client-id property"));
            } else {
                Binder binder = Binder.get(environment);
                String prefix = "security.oauth2.resource.";
                if (binder.bind(prefix + "jwt", STRING_OBJECT_MAP).isBound()) {
                    return ConditionOutcome.match(message.foundExactly("JWT resource configuration"));
                } else if (binder.bind(prefix + "jwk", STRING_OBJECT_MAP).isBound()) {
                    return ConditionOutcome.match(message.foundExactly("JWK resource configuration"));
                } else if (StringUtils.hasText(environment.getProperty(prefix + "user-info-uri"))) {
                    return ConditionOutcome.match(message.foundExactly("user-info-uri property"));
                } else if (StringUtils.hasText(environment.getProperty(prefix + "token-info-uri"))) {
                    return ConditionOutcome.match(message.foundExactly("token-info-uri property"));
                } else {
                    return ClassUtils.isPresent("org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration", (ClassLoader)null) && OAuth2ResourceServerConfiguration.AuthorizationServerEndpointsConfigurationBeanCondition.matches(context) ? ConditionOutcome.match(message.found("class").items(new Object[]{"org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration"})) : ConditionOutcome.noMatch(message.didNotFind("client ID, JWT resource or authorization server").atAll());
                }
            }
        }

        private boolean hasOAuthClientId(Environment environment) {
            return StringUtils.hasLength(environment.getProperty("security.oauth2.client.client-id"));
        }
    }

    protected static class ResourceSecurityConfigurer extends ResourceServerConfigurerAdapter {
        private ResourceServerProperties resource;

        public ResourceSecurityConfigurer(ResourceServerProperties resource) {
            this.resource = resource;
        }

        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(this.resource.getResourceId());
        }

        public void configure(HttpSecurity http) throws Exception {
            ((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
        }
    }
}

@Configuration
@ConditionalOnMissingBean({AuthorizationServerEndpointsConfiguration.class})
public class ResourceServerTokenServicesConfiguration {


    @Configuration
    @Conditional({ResourceServerTokenServicesConfiguration.RemoteTokenCondition.class})
    protected static class RemoteTokenServicesConfiguration {
        protected RemoteTokenServicesConfiguration() {
        }

        @Configuration
        @ConditionalOnMissingClass({"org.springframework.social.connect.support.OAuth2ConnectionFactory"})
        @Conditional({ResourceServerTokenServicesConfiguration.NotTokenInfoCondition.class})
        protected static class UserInfoTokenServicesConfiguration {
            private final ResourceServerProperties sso;
            private final OAuth2RestOperations restTemplate;
            private final AuthoritiesExtractor authoritiesExtractor;
            private final PrincipalExtractor principalExtractor;

            public UserInfoTokenServicesConfiguration(ResourceServerProperties sso, UserInfoRestTemplateFactory restTemplateFactory, ObjectProvider<AuthoritiesExtractor> authoritiesExtractor, ObjectProvider<PrincipalExtractor> principalExtractor) {
                this.sso = sso;
                this.restTemplate = restTemplateFactory.getUserInfoRestTemplate();
                this.authoritiesExtractor = (AuthoritiesExtractor)authoritiesExtractor.getIfAvailable();
                this.principalExtractor = (PrincipalExtractor)principalExtractor.getIfAvailable();
            }

            @Bean
            @ConditionalOnMissingBean({ResourceServerTokenServices.class})
            public UserInfoTokenServices userInfoTokenServices() {
                UserInfoTokenServices services = new UserInfoTokenServices(this.sso.getUserInfoUri(), this.sso.getClientId());
                services.setRestTemplate(this.restTemplate);
                services.setTokenType(this.sso.getTokenType());
                if (this.authoritiesExtractor != null) {
                    services.setAuthoritiesExtractor(this.authoritiesExtractor);
                }

                if (this.principalExtractor != null) {
                    services.setPrincipalExtractor(this.principalExtractor);
                }

                return services;
            }
        }

        @Configuration
        @ConditionalOnClass({OAuth2ConnectionFactory.class})
        @Conditional({ResourceServerTokenServicesConfiguration.NotTokenInfoCondition.class})
        protected static class SocialTokenServicesConfiguration {
            private final ResourceServerProperties sso;
            private final OAuth2ConnectionFactory<?> connectionFactory;
            private final OAuth2RestOperations restTemplate;
            private final AuthoritiesExtractor authoritiesExtractor;
            private final PrincipalExtractor principalExtractor;

            public SocialTokenServicesConfiguration(ResourceServerProperties sso, ObjectProvider<OAuth2ConnectionFactory<?>> connectionFactory, UserInfoRestTemplateFactory restTemplateFactory, ObjectProvider<AuthoritiesExtractor> authoritiesExtractor, ObjectProvider<PrincipalExtractor> principalExtractor) {
                this.sso = sso;
                this.connectionFactory = (OAuth2ConnectionFactory)connectionFactory.getIfAvailable();
                this.restTemplate = restTemplateFactory.getUserInfoRestTemplate();
                this.authoritiesExtractor = (AuthoritiesExtractor)authoritiesExtractor.getIfAvailable();
                this.principalExtractor = (PrincipalExtractor)principalExtractor.getIfAvailable();
            }

            @Bean
            @ConditionalOnBean({ConnectionFactoryLocator.class})
            @ConditionalOnMissingBean({ResourceServerTokenServices.class})
            public SpringSocialTokenServices socialTokenServices() {
                return new SpringSocialTokenServices(this.connectionFactory, this.sso.getClientId());
            }

            @Bean
            @ConditionalOnMissingBean({ConnectionFactoryLocator.class, ResourceServerTokenServices.class})
            public UserInfoTokenServices userInfoTokenServices() {
                UserInfoTokenServices services = new UserInfoTokenServices(this.sso.getUserInfoUri(), this.sso.getClientId());
                services.setTokenType(this.sso.getTokenType());
                services.setRestTemplate(this.restTemplate);
                if (this.authoritiesExtractor != null) {
                    services.setAuthoritiesExtractor(this.authoritiesExtractor);
                }

                if (this.principalExtractor != null) {
                    services.setPrincipalExtractor(this.principalExtractor);
                }

                return services;
            }
        }

        @Configuration
        @Conditional({ResourceServerTokenServicesConfiguration.TokenInfoCondition.class})
        protected static class TokenInfoServicesConfiguration {
            private final ResourceServerProperties resource;

            protected TokenInfoServicesConfiguration(ResourceServerProperties resource) {
                this.resource = resource;
            }

            @Bean
            public RemoteTokenServices remoteTokenServices() {
                RemoteTokenServices services = new RemoteTokenServices();
                services.setCheckTokenEndpointUrl(this.resource.getTokenInfoUri());
                services.setClientId(this.resource.getClientId());
                services.setClientSecret(this.resource.getClientSecret());
                return services;
            }
        }
    }
}

@Configuration
@ConditionalOnMissingBean(AuthorizationServerEndpointsConfiguration.class) // 容器中没有 AuthorizationServerEndpointsConfiguration 实例
public class ResourceServerTokenServicesConfiguration {
    
    // 注入对应的 ResourceServerTokenServices
}
// 关于资源服务器自定义配置
public class AutoResourceServerConfiguration implements ResourceServerConfigurer {

    private final RemoteTokenServices remoteTokenServices;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); // 默认访问令牌转换器
        UserAuthenticationConverter userTokenConverter = new EnhanceUserAuthenticationConverter(); // 自定义增强用户认证转换器
        accessTokenConverter.setUserTokenConverter(userTokenConverter);
        // 增强用户认证转换器
        remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
        // 使用远程令牌服务
        resources.tokenServices(remoteTokenServices);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and().csrf().disable();
    }
}
// 关于资源服务器检验token

// 对所有需要令牌的资源生效
OAuth2AuthenticationProcessingFilter  
// 使用BearerTokenExtractor在请求头中提取token
BearerTokenExtractor.extract()  
// bearer token 生成预认证令牌 PreAuthenticatedAuthenticationToken 
// 使用OAuth2AuthenticationManager认证
OAuth2AuthenticationManager.authenticate()  
// 使用远程token服务加载令牌 默认使用DefaultTokenServices 可以通过 
// ResourceServerSecurityConfigurer.tokenServices  配置自定义资源服务器
ResourceServerConfigurer.configure 
// 加载令牌
RemoteTokenServices.loadAuthentication() 
// 默认访问令牌转换器
DefaultAccessTokenConverter.extractAuthentication()
// 默认用户认证转换器
DefaultUserAuthenticationConverter.extractAuthentication() 
// 至此 用户认证信息 已经成功提取到
// 关于资源服务器是如何配置 OAuth2AuthenticationProcessingFilter 到容器的
@EnableResourceServer 
// 注入ResourceServerConfiguration到容器
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter implements Ordered{
    protected void configure(HttpSecurity http) -> { 
ResourceServerTokenServices services = this.resolveTokenServices();
        // 配置资源服务安全配置
        ResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer(){
            public void configure(HttpSecurity http){
            // 配置 O Auth 2身份验证处理过滤器
                AuthenticationManager oauthAuthenticationManager =                 this.oauthAuthenticationManager(http);
                this.resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();
             this.resourcesServerFilter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
            this.resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);
        }
    };
    http.apply(resources);
}
}
// 至此过滤器配置完成

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值