1. 创建 Spring Boot 项目
首先,我们需要创建一个新的 Spring Boot 项目,并添加如下的依赖:
代码语言:javascript复制phpCopy code<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
2. 配置 OAuth2 认证服务器
在 Spring Boot 项目的 application.yml 或 application.properties 文件中添加 OAuth2 认证服务器的配置:
代码语言:javascript复制yamlCopy codesecurity:
oauth2:
client:
clientId: clientapp
clientSecret: secret
authorizedGrantTypes: authorization_code,refresh_token,password
scopes: openid,read,write
authorization:
tokenKeyAccess: hasAuthority('ROLE_TRUSTED_CLIENT')
checkTokenAccess: hasAuthority('ROLE_TRUSTED_CLIENT')
3. 创建授权服务器
创建一个授权服务器类,继承 AuthorizationServerConfigurerAdapter 类,实现其中的 configure() 方法。
代码语言:javascript复制javaCopy code@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientapp")
.secret("{noop}secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("openid", "read", "write")
.accessTokenValiditySeconds(120)
.refreshTokenValiditySeconds(600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123456");
return converter;
}
}
4. 创建资源服务器
创建一个资源服务器类,继承 ResourceServerConfigurerAdapter 类,实现其中的 configure() 方法和 configure(ResourceServerSecurityConfigurer resources) 方法。
代码语言:javascript复制@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("resource-server-rest-api").stateless(true);
}
}
5. 创建安全配置类
创建一个安全配置类,继承 WebSecurityConfigurerAdapter 类,实现其中的 configure() 方法。
代码语言:javascript复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
}
6. 创建控制器
创建一个控制器类,实现一个简单的 RESTful API 接口。
代码语言:javascript复制@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
@GetMapping("/user")
public String user(Principal principal) {
return "Hello, " principal.getName();
}
}
7. 运行测试
现在我们已经完成了 OAuth2 认证服务器和资源服务器的配置,可以启动项目并测试了。首先访问 http://localhost:8080/oauth/token ,传递以下参数进行认证:
代码语言:javascript复制POST /oauth/token HTTP/1.1
Host: localhost:8080
Authorization: Basic Y2xpZW50YXBwOnNlY3JldA==
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=user&password=password
这将返回一个包含访问令牌和刷新令牌的 JSON 响应:
代码语言:javascript复制{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 119,
"scope": "openid read write"
}
接下来,我们可以使用这个访问令牌访问资源服务器的 API 接口,例如 http://localhost:8081/api/hello ,在请求头中加入以下内容:
代码语言:javascript复制GET /api/hello HTTP/1.1
Host: localhost:8081
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
这将返回以下响应:
代码语言:javascript复制Copy codeHello, World!
如果我们访问 http://localhost:8081/api/user ,在请求头中加入访问令牌,将返回以下响应:
代码语言:javascript复制sqlCopy codeHello, user
这表示我们已经成功访问了受 OAuth2 保护的资源服务器。