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
public OAuth2ClientContextFilter oauth2ClientContextFilter() {
OAuth2ClientContextFilter filter
= new OAuth2ClientContextFilter();
return filter;
}

@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
protected AccessTokenRequest accessTokenRequest(@Value("#{request.parameterMap}")
Map
<String, String[]> parameters, @Value("#{request.getAttribute('currentUri')}")
String currentUri) {
DefaultAccessTokenRequest request
= new DefaultAccessTokenRequest(parameters);
request.setCurrentUri(currentUri);
return request;
}

@Configuration
protected static class OAuth2ClientContextConfiguration {

@Resource
@Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;

@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new 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
private ClientDetailsService clientDetailsService;

@Autowired
private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

@PostConstruct
public void init() {
for (AuthorizationServerConfigurer configurer : configurers) {
try {
configurer.configure(endpoints);
}
catch (Exception e) {
throw new IllegalStateException("Cannot configure enpdoints", e);
}
}
endpoints.setClientDetailsService(clientDetailsService);
}

复制代码

 

 

复制代码
    @Component
    protected static class TokenKeyEndpointRegistrar implements BeanDefinitionRegistryPostProcessor {

private BeanDefinitionRegistry registry;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] names
= BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
JwtAccessTokenConverter.
class, false, false);
if (names.length > 0) {
BeanDefinitionBuilder builder
= BeanDefinitionBuilder.rootBeanDefinition(TokenKeyEndpoint.class);
builder.addConstructorArgReference(names[
0]);
registry.registerBeanDefinition(TokenKeyEndpoint.
class.getName(), builder.getBeanDefinition());
}
}

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
}

}

复制代码

2.2 AuthorizationServerSecurityConfiguration

复制代码
@Configuration
@Order(0)
@Import({ ClientDetailsServiceConfiguration.class, AuthorizationServerEndpointsConfiguration.class })
public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

@Autowired
private ClientDetailsService clientDetailsService;

@Autowired
private AuthorizationServerEndpointsConfiguration endpoints;

@Autowired
public void configure(ClientDetailsServiceConfigurer clientDetails) throws Exception {
for (AuthorizationServerConfigurer configurer : configurers) {
configurer.configure(clientDetails);
}
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Over-riding to make sure this.disableLocalConfigureAuthenticationBldr = false
// This will ensure that when this configurer builds the AuthenticationManager it will not attempt
// to find another 'Global' AuthenticationManager in the ApplicationContext (if available),
// and set that as the parent of this 'Local' AuthenticationManager.
// This AuthenticationManager should only be wired up with an AuthenticationProvider
// composed of the ClientDetailsService (wired in this configuration) for authenticating 'clients' only.
}

@Override
protected void configure(HttpSecurity http) throws Exception {
AuthorizationServerSecurityConfigurer configurer
= new AuthorizationServerSecurityConfigurer();
FrameworkEndpointHandlerMapping handlerMapping
= endpoints.oauth2EndpointHandlerMapping();
http.setSharedObject(FrameworkEndpointHandlerMapping.
class, handlerMapping);
configure(configurer);
http.apply(configurer);
String tokenEndpointPath
= handlerMapping.getServletPath("/oauth/token");
String tokenKeyPath
= handlerMapping.getServletPath("/oauth/token_key");
String checkTokenPath
= handlerMapping.getServletPath("/oauth/check_token");
if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
UserDetailsService userDetailsService
= http.getSharedObject(UserDetailsService.class);
endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
}
// @formatter:off
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);
}

protected void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
for (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("unchecked")
private void registerDefaultAuthenticationEntryPoint(HttpSecurity http) {
ExceptionHandlingConfigurer
<HttpSecurity> exceptionHandling = http
.getConfigurer(ExceptionHandlingConfigurer.
class);
if (exceptionHandling == null) {
return;
}
ContentNegotiationStrategy contentNegotiationStrategy
= http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy
= new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher preferredMatcher
= new 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);
}

复制代码

2.configure

复制代码
@Override
    public void configure(HttpSecurity http) throws Exception {

AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);
resourcesServerFilter
= new OAuth2AuthenticationProcessingFilter();
resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);
if (eventPublisher != null) {
resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher);
}
if (tokenExtractor != null) {
resourcesServerFilter.setTokenExtractor(tokenExtractor);
}
resourcesServerFilter
= postProcess(resourcesServerFilter);
resourcesServerFilter.setStateless(stateless);

// @formatter:off
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
posted @ 2019-06-12 15:00  星朝  阅读(2425)  评论(0)    收藏  举报