如何将 spring-security-oauth 服务器添加到具有经典身份验证的现有 Web 应用程序?
How to add spring-security-oauth server to an existing web application with classic authentication?
我有一个基于经典 cookie 的身份验证的 Web 应用程序。这是它的配置方式:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
http.authorizeRequests()
.antMatchers("/some/restricted/urls*").access("hasRole('admin')")
.antMatchers("/some/public/urls").permitAll()
.antMatchers("/**").access("hasRole('registered')");
}
@Autowired
protected void configureAuthenticationManager(final AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
现在我想启用外部应用程序以使用 OAuth2 访问我的一些用户数据。首先,我像这样添加身份验证:
@Configuration
@EnableAuthorizationServer
public class OAuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager auth;
@Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Bean
public JdbcClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final ApprovalStoreUserApprovalHandler approvalHandler = new ApprovalStoreUserApprovalHandler();
approvalHandler.setClientDetailsService(clientDetailsService());
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(auth)
.tokenStore(tokenStore())
.userApprovalHandler(approvalHandler)
.pathMapping("/oauth/confirm_access", "/api/oauth2/confirm_access")
.pathMapping("/oauth/token", "/api/oauth2/token")
.pathMapping("/oauth/check_token", "/api/oauth2/check_token")
.pathMapping("/oauth/token_key", "/api/oauth2/token_key")
.pathMapping("/oauth/authorize", "/api/oauth2/authorize");
}
}
一切似乎都运行良好。我的网络应用程序总体上似乎可以正常工作,我可以获得代码并将其交换为访问令牌。仅访问令牌本身是无用的,因此我想添加一项需要有效访问令牌的服务。为此,我添加了以下内容:
@Configuration
@EnableResourceServer
public class Oauth2ResourcesConfigurationAdapter extends ResourceServerConfigurerAdapter {
@Autowired
private AuthenticationManager auth;
@Autowired
private OAuthServerConfig oAuthServerConfig;
@Override
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
resources
.authenticationManager(auth)
.tokenStore(oAuthServerConfig.tokenStore());
}
}
然而这让我例外:
Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer@6dd1c3ed to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:192)
我阅读了调试过的源代码并 google 尽我所能,但我就是无法弄清楚这里发生了什么。我发现的最接近的提示是 this ticket on GitHub,但是它没有对问题进行解释,而且我按照票证中的建议编写自己的配置非常不成功,可能是因为我不知道问题是什么是,因此我需要改变。
同时 robsilvia 在上面列出的 github 工单中给出了答案。简而言之,它说,必须将此方法添加到 Oauth2ResourcesConfigurationAdapter
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
然而,这导致我的 oauth 配置干扰了我的经典 Web 应用程序安全配置,该配置不再正常工作。但是我确实发现了 "multiple HttpSecurity",因此我最终通过使用这个变体解决了这个问题:
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/path/to/oauth/endpoints/*"),
new AntPathRequestMatcher("/oauth/protected/resource")
))
.authorizeRequests().anyRequest().authenticated();
}
我有一个基于经典 cookie 的身份验证的 Web 应用程序。这是它的配置方式:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
http.authorizeRequests()
.antMatchers("/some/restricted/urls*").access("hasRole('admin')")
.antMatchers("/some/public/urls").permitAll()
.antMatchers("/**").access("hasRole('registered')");
}
@Autowired
protected void configureAuthenticationManager(final AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
现在我想启用外部应用程序以使用 OAuth2 访问我的一些用户数据。首先,我像这样添加身份验证:
@Configuration
@EnableAuthorizationServer
public class OAuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager auth;
@Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Bean
public JdbcClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final ApprovalStoreUserApprovalHandler approvalHandler = new ApprovalStoreUserApprovalHandler();
approvalHandler.setClientDetailsService(clientDetailsService());
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(auth)
.tokenStore(tokenStore())
.userApprovalHandler(approvalHandler)
.pathMapping("/oauth/confirm_access", "/api/oauth2/confirm_access")
.pathMapping("/oauth/token", "/api/oauth2/token")
.pathMapping("/oauth/check_token", "/api/oauth2/check_token")
.pathMapping("/oauth/token_key", "/api/oauth2/token_key")
.pathMapping("/oauth/authorize", "/api/oauth2/authorize");
}
}
一切似乎都运行良好。我的网络应用程序总体上似乎可以正常工作,我可以获得代码并将其交换为访问令牌。仅访问令牌本身是无用的,因此我想添加一项需要有效访问令牌的服务。为此,我添加了以下内容:
@Configuration
@EnableResourceServer
public class Oauth2ResourcesConfigurationAdapter extends ResourceServerConfigurerAdapter {
@Autowired
private AuthenticationManager auth;
@Autowired
private OAuthServerConfig oAuthServerConfig;
@Override
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
resources
.authenticationManager(auth)
.tokenStore(oAuthServerConfig.tokenStore());
}
}
然而这让我例外:
Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer@6dd1c3ed to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:192)
我阅读了调试过的源代码并 google 尽我所能,但我就是无法弄清楚这里发生了什么。我发现的最接近的提示是 this ticket on GitHub,但是它没有对问题进行解释,而且我按照票证中的建议编写自己的配置非常不成功,可能是因为我不知道问题是什么是,因此我需要改变。
同时 robsilvia 在上面列出的 github 工单中给出了答案。简而言之,它说,必须将此方法添加到 Oauth2ResourcesConfigurationAdapter
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
然而,这导致我的 oauth 配置干扰了我的经典 Web 应用程序安全配置,该配置不再正常工作。但是我确实发现了 "multiple HttpSecurity",因此我最终通过使用这个变体解决了这个问题:
@Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/path/to/oauth/endpoints/*"),
new AntPathRequestMatcher("/oauth/protected/resource")
))
.authorizeRequests().anyRequest().authenticated();
}