Oauth2 资源服务器重叠 Spring Security 配置
Posted
技术标签:
【中文标题】Oauth2 资源服务器重叠 Spring Security 配置【英文标题】:Oauth2 Resource server overlap Spring Security configuration 【发布时间】:2017-03-25 12:29:59 【问题描述】:我正在尝试在 java config 上配置 Spring Security 和 OAuth2。我正在使用 Spring Security 版本 4.0.4.RELEASE 和 OAuth2 版本 2.0.11.RELEASE。
Spring Security 配置运行良好。我也可以使用 OAuth2 AuthorizationServer 获取访问令牌,但我的 ResourceServer 无法正常工作。当我设置注释 @EnableResourceServer 时,我只能检查我的访问令牌和其他我无法打开的 URL(安全配置和 AuthorizationServer 配置不起作用)。我看到以下错误:
<oauth>
<error_description>
An Authentication object was not found in the SecurityContext
</error_description>
<error>unauthorized</error>
</oauth>
如果我删除注释 @EnableResourceServer,我的 ResourceServer 不会检查访问令牌。它只是重定向到身份验证页面。
这是我的代码:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class GlobalSecurityConfig extends GlobalMethodSecurityConfiguration
@Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Autowired
@Qualifier("authUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
@Autowired
@Qualifier("permissionEvaluator")
private PermissionEvaluator permissionEvaluator;
@Bean
public DefaultMethodSecurityExpressionHandler expressionHandler()
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setDefaultRolePrefix("");
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler()
return expressionHandler();
安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Bean(name = "clientAuthenticationEntryPoint")
public OAuth2AuthenticationEntryPoint oauthAuthenticationEntryPoint()
OAuth2AuthenticationEntryPoint entry = new OAuth2AuthenticationEntryPoint();
entry.setRealmName("myapp/client");
entry.setTypeName("Basic");
return entry;
@Autowired
@Qualifier("webExpressionHandler")
private DefaultWebSecurityExpressionHandler expressionHandler;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Bean
public SessionRegistry sessionRegistry()
return new SessionRegistryImpl();
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring()
.antMatchers("/html/**", "/webapi/**");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.requestMatchers().antMatchers("/admin/**", "/**")
.and()
.authorizeRequests()
.expressionHandler(expressionHandler)
.antMatchers("/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/1/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/profile**").authenticated()
.antMatchers("/oauth/authorize").authenticated()
.and()
.formLogin().loginPage("/login")
.failureUrl("/login?error=1")
.loginProcessingUrl("/login-attempt")
.defaultSuccessUrl("/", false)
.and()
.sessionManagement()
.sessionFixation().migrateSession()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling()
.accessDeniedPage("/access-denied")
.and()
.csrf();
Oauth 配置:
@Configuration
public class Oauth
@Configuration
@EnableResourceServer
public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
private static final String RESOURCE_ID = "my_oauth_server";
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
resources.resourceId(RESOURCE_ID);
@Override
public void configure(HttpSecurity http) throws Exception
http
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.regexMatchers("/api/v0/.*").authenticated()
.antMatchers("/**").denyAll()
;
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private AuthorizationCodeServices verificationCodeService;
@Autowired
@Qualifier("clientDetails")
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("tokenStore")
private TokenStore tokenStore;
@Bean(name = "tokenServices")
public DefaultTokenServices tokenServices()
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
return tokenServices;
@Bean
public ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter() throws Exception
ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients.withClientDetails(clientDetailsService);
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.authenticationManager(authenticationManager);
endpoints.authorizationCodeServices(verificationCodeService);
endpoints.tokenServices(tokenServices());
endpoints.reuseRefreshTokens(true);
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
oauthServer.tokenKeyAccess("permitAll()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.realm("myapp/client");
oauthServer.addTokenEndpointAuthenticationFilter(clientCredentialsTokenEndpointFilter());
oauthServer.allowFormAuthenticationForClients();
因此,ResourceServer 配置与其他配置重叠。我该如何解决?如有任何帮助,我将不胜感激。
【问题讨论】:
【参考方案1】:我看到您想用访问令牌保护一些端点,而用普通表单登录保护其他端点。
您能否尝试通过http.requestMatcher(new AntPathRequestMatcher("/api/v0/**"))...
之类的方式将ResourceServerConfiguration
的适用性限制为仅适用于某些端点。对SecurityConfig
执行相同的操作,但对于您希望它处理的端点。
【讨论】:
嗨@sofiaguyang,感谢您提出一个想法。我已经限制了ResourceServerConfiguration
和SecurityConfig
的适用性。现在我看不到错误An Authentication object was not found in the SecurityContext
。但是我丢失了一个登录按钮。我不明白我的代码有什么问题。
一般流程是:如果您访问受 OAuth2 保护的端点,您必须提供访问令牌,否则您将收到未经授权/禁止的响应。您可以通过从 /oauth/authorize 检索身份验证代码并将身份验证代码与来自 /oauth/token
的访问令牌交换来获得访问令牌。最初,当用户访问/oauth/authorize
时,用户尚未经过身份验证。但是因为你必须通过身份验证才能授权,所以你会被重定向到登录页面。
谢谢!您对登录按钮有什么想法吗?或者我需要尝试另一种方式来配置 ResourceServer?这是我的配置:http.requestMatcher(new AntPathRequestMatcher("/api/v0/**")).authorizeRequests().antMatchers("/api/v0/**").authenticated().antMatchers("/**").denyAll();
以上是关于Oauth2 资源服务器重叠 Spring Security 配置的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security OAuth2 资源服务器重试/弹性
使用Spring boot的OAuth2认证服务器和资源服务器