Spring Boot 2.0下用Spring Security OAuth2保护REST API遇问题求助
嘿,我刚好踩过Spring Boot 2.x迁移OAuth2授权服务器配置的坑,给你梳理下核心变化和完整实现方案,帮你搞定这个问题:
在Spring Boot 2.x中用Spring Security OAuth2保护REST API
首先得明确:Spring Boot 2.x对OAuth2的支持做了不少调整,尤其是授权服务器的配置逻辑,和你参考的1.5版本教程差异不小。下面一步步来:
1. 先调整Maven依赖
Spring Boot 2.x不再默认打包OAuth2相关 starter,你需要手动添加依赖。如果是用传统的Spring Security OAuth2模块(注意这个模块现在进入维护状态,后续推荐迁移到官方新的Spring Authorization Server,但针对2.0版本先按传统方案来),POM配置如下:
<dependencies> <!-- 基础Web依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Security OAuth2核心依赖 --> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.8.RELEASE</version> </dependency> <!-- Spring Security基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
2. 重写授权服务器配置
你之前用的AuthorizationServerConfigurerAdapter在2.x中还能用,但配置细节有变化,比如密码处理、端点权限等。给你一个完整的配置类示例:
import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { // 内存存储令牌(测试用,生产建议用JWT或数据库存储) private final TokenStore tokenStore = new InMemoryTokenStore(); // 如果需要密码模式,记得注入AuthenticationManager并在endpoints中配置 // @Autowired // private AuthenticationManager authenticationManager; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 允许匿名访问令牌获取端点,允许客户端用表单提交方式拿令牌 security.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 内存存储客户端信息(生产建议存数据库) clients.inMemory() .withClient("your-client-id") .secret("{noop}your-client-secret") // 2.x要求密码必须加密,{noop}表示明文(仅测试) .authorizedGrantTypes("password", "refresh_token") // 支持的授权模式:密码、刷新令牌 .scopes("read", "write") // 权限范围 .accessTokenValiditySeconds(3600) // 令牌有效期1小时 .refreshTokenValiditySeconds(86400); // 刷新令牌有效期1天 } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(tokenStore); // 密码模式需要添加这一行 // endpoints.authenticationManager(authenticationManager); } }
3. 配置资源服务器(保护你的API)
接下来要配置资源服务器,指定哪些接口需要OAuth2令牌才能访问:
import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { private static final String RESOURCE_ID = "your-resource-id"; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(RESOURCE_ID).stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**").authenticated() // 保护/api下所有接口 .anyRequest().permitAll(); // 其他接口允许匿名访问 } }
4. 配置基础Spring Security认证
还需要配置用户信息,这里用内存用户做测试(生产建议用数据库):
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 密码模式需要暴露AuthenticationManager @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("test-user") .password("{noop}test-pass") .roles("USER"); } // 测试用明文密码编码器,生产必须用BCryptPasswordEncoder! @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } }
核心差异提醒
- 密码编码强制要求:Spring Boot 2.x默认开启密码加密校验,所以客户端和用户密码要么加
{noop}前缀(仅测试),要么用PasswordEncoder加密后存储。 - 依赖变更:1.5的
spring-boot-starter-oauth2在2.x中被拆分,需要手动引入spring-security-oauth2。 - 后续迁移提示:
AuthorizationServerConfigurerAdapter在Spring Security 5.1+被标记为弃用,官方推荐用Spring Authorization Server,但在2.0版本中这个配置完全可用。
测试验证
写个简单的测试接口:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class TestApiController { @GetMapping("/hello") public String hello() { return "Hello from OAuth2 Protected API!"; } }
然后用POST请求http://localhost:8080/oauth/token,用form-data传参数:
- username: test-user
- password: test-pass
- grant_type: password
- client_id: your-client-id
- client_secret: your-client-secret
拿到access_token后,请求http://localhost:8080/api/hello,在请求头加Authorization: Bearer {你的access_token},就能正常访问啦。
内容的提问来源于stack exchange,提问作者Paras
相关产品推荐
相关产品推荐

