zoukankan      html  css  js  c++  java
  • spring-security-oauth2注解详解

    spring-security-oauth2支持的注解有:

    1.EnableOAuth2Client

    适用于使用spring security,并且想从Oauth2认证服务器来获取授权的web应用环境代码中,它启用了一个Oauth2 客户端配置。为了更好的利用这个特性,需要在客户端应用中的DelegatingFilterProxy(代理一个名为oauth2ClientContextFilter)增加一个servlet filter。当filter配置到client app时,可以使用注解@AccessTokenRequest提供的另一个bean来创建一个Oauth2RequestTemplate。示例:

    复制代码
      @Configuration
      @EnableOAuth2Client
      public class RemoteResourceConfiguration {
    

    @Bean
    public OAuth2RestOperations restTemplate(OAuth2ClientContext oauth2ClientContext) {
    return new OAuth2RestTemplate(remote(), oauth2ClientContext);
    }

    }

    复制代码

    Client App使用client credential授权,不需要AccessTokenRequest或者域内RestOperation(对app来说,状态是全局的),但在需要时仍然使用filter来触发OAuth2RestOperation来获取token。使用密码授权的app需要在RestOperation动作之前为OAuth2ProtectedResouceDetail设置认证属性,这就是说,resouce detail 本身也需要session(假设系统中有多个用户)。

    复制代码
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(OAuth2ClientConfiguration.class)
    public @interface EnableOAuth2Client {
    

    }

    复制代码

    实现OAuth2ClientConfiguration

    复制代码
    @Configuration
    public class OAuth2ClientConfiguration {
    
    @Bean
    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> OAuth2ClientContextFilter oauth2ClientContextFilter() {
        OAuth2ClientContextFilter filter </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> OAuth2ClientContextFilter();
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> filter;
    }
    
    @Bean
    @Scope(value </span>= "request", proxyMode =<span style="color: #000000;"> ScopedProxyMode.INTERFACES)
    </span><span style="color: #0000ff;">protected</span> AccessTokenRequest accessTokenRequest(@Value("#{request.parameterMap}"<span style="color: #000000;">)
    Map</span>&lt;String, String[]&gt; parameters, @Value("#{request.getAttribute('currentUri')}"<span style="color: #000000;">)
    String currentUri) {
        DefaultAccessTokenRequest request </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> DefaultAccessTokenRequest(parameters);
        request.setCurrentUri(currentUri);
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> request;
    }
    
    @Configuration
    </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> OAuth2ClientContextConfiguration {
        
        @Resource
        @Qualifier(</span>"accessTokenRequest"<span style="color: #000000;">)
        </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> AccessTokenRequest accessTokenRequest;
        
        @Bean
        @Scope(value </span>= "session", proxyMode =<span style="color: #000000;"> ScopedProxyMode.INTERFACES)
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> OAuth2ClientContext oauth2ClientContext() {
            </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> DefaultOAuth2ClientContext(accessTokenRequest);
        }
        
    }
    

    }

    复制代码

    2. EnableAuthorizationServer

    工具方法,用来在当前应用context里(必须是一个DispatcherServlet context)开启一个授权server(例如AuthorizationEndpoint)和一个TokenEndpoint。server的多个属性可以通过自定义AuthorizationServerConfigurer类型(如AuthorizationServerConfigurerAdapter的扩展)的Bean来定制。通过正常使用spring security的特色EnableWebSecurity,用户负责保证授权Endpoint(/oauth/authorize)的安全,但Token Endpoint(/oauth/token)将自动使用http basic的客户端凭证来保证安全。通过一个或者多个AuthorizationServerConfigurer提供一个ClientDetailService来注册client(必须)。

    复制代码
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
    public @interface EnableAuthorizationServer {
    

    }

    复制代码

    2.1 AuthorizationServerEndpointsConfiguration

    复制代码
        private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();
    
    @Autowired
    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> ClientDetailsService clientDetailsService;
    
    @Autowired
    </span><span style="color: #0000ff;">private</span> List&lt;AuthorizationServerConfigurer&gt; configurers =<span style="color: #000000;"> Collections.emptyList();
    
    @PostConstruct
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> init() {
        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (AuthorizationServerConfigurer configurer : configurers) {
            </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                configurer.configure(endpoints);
            } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
                </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IllegalStateException("Cannot configure enpdoints"<span style="color: #000000;">, e);
            }
        }
        endpoints.setClientDetailsService(clientDetailsService);
    }</span></pre>
    
    复制代码
    复制代码
        @Component
        protected static class TokenKeyEndpointRegistrar implements BeanDefinitionRegistryPostProcessor {
    
        </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> BeanDefinitionRegistry registry;
    
        @Override
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> BeansException {
            String[] names </span>=<span style="color: #000000;"> BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
                    JwtAccessTokenConverter.</span><span style="color: #0000ff;">class</span>, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">false</span><span style="color: #000000;">);
            </span><span style="color: #0000ff;">if</span> (names.length &gt; 0<span style="color: #000000;">) {
                BeanDefinitionBuilder builder </span>= BeanDefinitionBuilder.rootBeanDefinition(TokenKeyEndpoint.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
                builder.addConstructorArgReference(names[</span>0<span style="color: #000000;">]);
                registry.registerBeanDefinition(TokenKeyEndpoint.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getName(), builder.getBeanDefinition());
            }
        }
    
        @Override
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> BeansException {
            </span><span style="color: #0000ff;">this</span>.registry =<span style="color: #000000;"> registry;
        }
    
    }</span></pre>
    
    复制代码

    2.2 AuthorizationServerSecurityConfiguration

    复制代码
    @Configuration
    @Order(0)
    @Import({ ClientDetailsServiceConfiguration.class, AuthorizationServerEndpointsConfiguration.class })
    public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    @Autowired
    </span><span style="color: #0000ff;">private</span> List&lt;AuthorizationServerConfigurer&gt; configurers =<span style="color: #000000;"> Collections.emptyList();
    
    @Autowired
    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> ClientDetailsService clientDetailsService;
    
    @Autowired
    </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> AuthorizationServerEndpointsConfiguration endpoints;
    
    @Autowired
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> configure(ClientDetailsServiceConfigurer clientDetails) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (AuthorizationServerConfigurer configurer : configurers) {
            configurer.configure(clientDetails);
        }
    }
    
    @Override
    </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span> configure(AuthenticationManagerBuilder auth) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> Over-riding to make sure this.disableLocalConfigureAuthenticationBldr = false
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> This will ensure that when this configurer builds the AuthenticationManager it will not attempt
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> to find another 'Global' AuthenticationManager in the ApplicationContext (if available),
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> and set that as the parent of this 'Local' AuthenticationManager.
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> This AuthenticationManager should only be wired up with an AuthenticationProvider
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> composed of the ClientDetailsService (wired in this configuration) for authenticating 'clients' only.</span>
    

    }

    @Override
    </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span> configure(HttpSecurity http) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
        AuthorizationServerSecurityConfigurer configurer </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> AuthorizationServerSecurityConfigurer();
        FrameworkEndpointHandlerMapping handlerMapping </span>=<span style="color: #000000;"> endpoints.oauth2EndpointHandlerMapping();
        http.setSharedObject(FrameworkEndpointHandlerMapping.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">, handlerMapping);
        configure(configurer);
        http.apply(configurer);
        String tokenEndpointPath </span>= handlerMapping.getServletPath("/oauth/token"<span style="color: #000000;">);
        String tokenKeyPath </span>= handlerMapping.getServletPath("/oauth/token_key"<span style="color: #000000;">);
        String checkTokenPath </span>= handlerMapping.getServletPath("/oauth/check_token"<span style="color: #000000;">);
        </span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
            UserDetailsService userDetailsService </span>= http.getSharedObject(UserDetailsService.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
            endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
        }
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> @formatter:off</span>
    

    http
    .authorizeRequests()
    .antMatchers(tokenEndpointPath).fullyAuthenticated()
    .antMatchers(tokenKeyPath).access(configurer.getTokenKeyAccess())
    .antMatchers(checkTokenPath).access(configurer.getCheckTokenAccess())
    .and()
    .requestMatchers()
    .antMatchers(tokenEndpointPath, tokenKeyPath, checkTokenPath)
    .and()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
    // @formatter:on
    http.setSharedObject(ClientDetailsService.class, clientDetailsService);
    }

    </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span> configure(AuthorizationServerSecurityConfigurer oauthServer) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (AuthorizationServerConfigurer configurer : configurers) {
            configurer.configure(oauthServer);
        }
    }
    

    }

    复制代码

     3. EnableResourceServer

    Oauth2 资源服务器的便利方法,开启了一个spring security的filter,这个filter通过一个Oauth2的token进行认证请求。使用者应该增加这个注解,并提供一个ResourceServerConfigurer类型的Bean(例如通过ResouceServerConfigurerAdapter)来指定资源(url路径和资源id)的细节。为了利用这个filter,你必须在你的应用中的某些地方EnableWebSecurity,或者使用这个注解的地方,或者其他别的地方。

    这个注解创建了一个WebSecurityConfigurerAdapter,且自带了硬编码的order=3.在spring中,由于技术原因不能立即改变order的顺序,因此你必须在你的spring应用中避免使用order=3的其他WebSecurityConfigurerAdapter。

    复制代码
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(ResourceServerConfiguration.class)
    public @interface EnableResourceServer {
    

    }

    复制代码

    ResourceServerConfiguration

    复制代码
    @Override
        protected void configure(HttpSecurity http) throws Exception {
            ResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer();
            ResourceServerTokenServices services = resolveTokenServices();
            if (services != null) {
                resources.tokenServices(services);
            }
            else {
                if (tokenStore != null) {
                    resources.tokenStore(tokenStore);
                }
                else if (endpoints != null) {
                    resources.tokenStore(endpoints.getEndpointsConfigurer().getTokenStore());
                }
            }
            if (eventPublisher != null) {
                resources.eventPublisher(eventPublisher);
            }
            for (ResourceServerConfigurer configurer : configurers) {
                configurer.configure(resources);
            }
            // @formatter:off
            http.authenticationProvider(new AnonymousAuthenticationProvider("default"))
            // N.B. exceptionHandling is duplicated in resources.configure() so that
            // it works
            .exceptionHandling()
                    .accessDeniedHandler(resources.getAccessDeniedHandler()).and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    .csrf().disable();
            // @formatter:on
            http.apply(resources);
            if (endpoints != null) {
                // Assume we are in an Authorization Server
                http.requestMatcher(new NotOAuthRequestMatcher(endpoints.oauth2EndpointHandlerMapping()));
            }
            for (ResourceServerConfigurer configurer : configurers) {
                // Delegates can add authorizeRequests() here
                configurer.configure(http);
            }
            if (configurers.isEmpty()) {
                // Add anyRequest() last as a fall back. Spring Security would
                // replace an existing anyRequest() matcher with this one, so to
                // avoid that we only add it if the user hasn't configured anything.
                http.authorizeRequests().anyRequest().authenticated();
            }
        }
    复制代码

    ResourceServerSecurityConfigurer

    重新的两个方法

    1.init

    复制代码
    @Override
        public void init(HttpSecurity http) throws Exception {
            registerDefaultAuthenticationEntryPoint(http);
        }
    
    @SuppressWarnings(</span>"unchecked"<span style="color: #000000;">)
    </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> registerDefaultAuthenticationEntryPoint(HttpSecurity http) {
        ExceptionHandlingConfigurer</span>&lt;HttpSecurity&gt; exceptionHandling =<span style="color: #000000;"> http
                .getConfigurer(ExceptionHandlingConfigurer.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);
        </span><span style="color: #0000ff;">if</span> (exceptionHandling == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;
        }
        ContentNegotiationStrategy contentNegotiationStrategy </span>= http.getSharedObject(ContentNegotiationStrategy.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
        </span><span style="color: #0000ff;">if</span> (contentNegotiationStrategy == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
            contentNegotiationStrategy </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> HeaderContentNegotiationStrategy();
        }
        MediaTypeRequestMatcher preferredMatcher </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> MediaTypeRequestMatcher(contentNegotiationStrategy,
                MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
                MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA,
                MediaType.TEXT_XML);
        preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
        exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint), preferredMatcher);
    }</span></pre>
    
    复制代码

    2.configure

    复制代码
    @Override
        public void configure(HttpSecurity http) throws Exception {
    
        AuthenticationManager oauthAuthenticationManager </span>=<span style="color: #000000;"> oauthAuthenticationManager(http);
        <span style="color: #ff0000;">resourcesServerFilter </span></span><span style="color: #ff0000;">= new</span><span style="color: #000000;"><span style="color: #ff0000;"> OAuth2AuthenticationProcessingFilter();</span>
        resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
        resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);
        </span><span style="color: #0000ff;">if</span> (eventPublisher != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
            resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher);
        }
        </span><span style="color: #0000ff;">if</span> (tokenExtractor != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
            resourcesServerFilter.setTokenExtractor(tokenExtractor);
        }
        resourcesServerFilter </span>=<span style="color: #000000;"> postProcess(resourcesServerFilter);
        resourcesServerFilter.setStateless(stateless);
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> @formatter:off</span>
    

    http
    .authorizeRequests().expressionHandler(expressionHandler)
    .and()
    .addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.
    class)
    .exceptionHandling()
    .accessDeniedHandler(accessDeniedHandler)
    .authenticationEntryPoint(authenticationEntryPoint);
    // @formatter:on
    }

    复制代码

    其中OAuth2AuthenticationProcessingFilter:A pre-authentication filter for OAuth2 protected resources. Extracts an OAuth2 token from the incoming request and uses it to populate the Spring Security context with an {@link OAuth2Authentication} (if used in conjunction with an{@link OAuth2AuthenticationManager}).

    原文地址:https://www.cnblogs.com/davidwang456/p/6480681.html
  • 相关阅读:
    Java——字符串操作
    算法——Java实现队列
    算法——Java实现栈
    算法——线性表之链式存储结构
    算法——线性表之顺序存储结构
    Java——单双引号的区别
    Hystrix源码解析
    Eureka源码探索(一)-客户端服务端的启动和负载均衡
    dubbo源码研究(一)
    dubbo-springboot入门级demo
  • 原文地址:https://www.cnblogs.com/jpfss/p/11009717.html
Copyright © 2011-2022 走看看