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}).

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM