Spring Security 6 + OAuth 2.0实战:构建企业级认证授权体系 [复制链接]
发表于 7 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、Spring Security 6 与 OAuth 2.0 概述

Spring Security 6是Spring Security的最新主版本,全面支持OAuth 2.1和OpenID Connect 1.0。本文将实战演示怎样构建一个完备的OAuth 2.0授权服务器和资源服务器,实现安全的API认证与授权。
二、项目架构计划
  1. ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
  2. │   客户端应用     │────▶│  OAuth 2.0      │────▶│   资源服务器    │
  3. │  (Vue/React)    │◀────│  授权服务器      │◀────│  (REST API)    │
  4. └─────────────────┘     └─────────────────┘     └─────────────────┘
  5.          │                       │                       │
  6.          └───────────────────────┴───────────────────────┘
  7.                     JWT Token 认证流程
复制代码
三、授权服务器搭建

3.1 添加依赖
  1. <dependencies>
  2.     <dependency>
  3.         <groupId>org.springframework.security</groupId>
  4.         spring-security-oauth2-authorization-server</artifactId>
  5.         <version>1.3.0</version>
  6.     </dependency>
  7.     <dependency>
  8.         <groupId>org.springframework.boot</groupId>
  9.         spring-boot-starter-security</artifactId>
  10.     </dependency>
  11.     <dependency>
  12.         <groupId>org.springframework.boot</groupId>
  13.         spring-boot-starter-web</artifactId>
  14.     </dependency>
  15. </dependencies>
复制代码
3.2 授权服务器设置
  1. @Configuration
  2. @EnableWebSecurity
  3. public class AuthorizationServerConfig {
  4.     @Bean @Order(1)
  5.     public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
  6.         OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
  7.         http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults());
  8.         return http.build();
  9.     }
  10.     @Bean @Order(2)
  11.     public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
  12.         http.authorizeHttpRequests(auth -> auth.requestMatchers("/login").permitAll().anyRequest().authenticated())
  13.             .formLogin(Customizer.withDefaults());
  14.         return http.build();
  15.     }
  16.     @Bean
  17.     public RegisteredClientRepository registeredClientRepository() {
  18.         RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
  19.             .clientId("my-client").clientSecret("{noop}my-secret")
  20.             .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
  21.             .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
  22.             .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
  23.             .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
  24.             .redirectUri("http://127.0.0.1:8080/login/oauth2/code/my-client")
  25.             .scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).scope("api.read").scope("api.write")
  26.             .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();
  27.         return new InMemoryRegisteredClientRepository(client);
  28.     }
  29.     @Bean
  30.     public JWKSource<SecurityContext> jwkSource() {
  31.         RSAKey rsaKey = generateRsaKey();
  32.         return (jwkSelector, context) -> jwkSelector.select(new JWKSet(rsaKey));
  33.     }
  34.     private static RSAKey generateRsaKey() {
  35.         try {
  36.             KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  37.             return new RSAKey.Builder((RSAPublicKey)keyPair.getPublic())
  38.                 .privateKey((RSAPrivateKey)keyPair.getPrivate()).keyID(UUID.randomUUID().toString()).build();
  39.         } catch (Exception e) { throw new IllegalStateException(e); }
  40.     }
  41. }
复制代码
四、资源服务器搭建

4.1 设置文件
  1. spring:
  2.   security:
  3.     oauth2:
  4.       resourceserver:
  5.         jwt:
  6.           issuer-uri: http://localhost:9000
  7.           jwk-set-uri: http://localhost:9000/.well-known/jwks.json
复制代码
4.2 安全设置
  1. @Configuration
  2. @EnableWebSecurity
  3. public class ResourceServerConfig {
  4.     @Bean
  5.     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  6.         http.authorizeHttpRequests(auth -> auth
  7.             .requestMatchers("/api/public/**").permitAll()
  8.             .requestMatchers("/api/admin/**").hasRole("ADMIN")
  9.             .anyRequest().authenticated())
  10.             .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
  11.         return http.build();
  12.     }
  13. }
复制代码
4.3 受掩护API示例
  1. @RestController
  2. @RequestMapping("/api")
  3. public class ApiController {
  4.     @GetMapping("/user/profile")
  5.     public Map<String, Object> userProfile(@AuthenticationPrincipal Jwt jwt) {
  6.         return Map.of("username", jwt.getSubject(), "scopes", jwt.getClaimAsStringList("scope"));
  7.     }
  8.     @GetMapping("/admin/data")
  9.     @PreAuthorize("hasRole('ADMIN')")
  10.     public String adminData() { return "Admin only data"; }
  11. }
复制代码
五、客户端测试

5.1 获取Token
  1. curl -X POST http://localhost:9000/oauth2/token -H "Content-Type: application/x-www-form-urlencoded" -u "my-client:my-secret" -d "grant_type=client_credentials" -d "scope=api.read"
  2. # 返回: {"access_token":"eyJ...","token_type":"Bearer","expires_in":300}
复制代码
5.2 调用API
  1. curl -H "Authorization: Bearer eyJ..." http://localhost:8081/api/user/profile
  2. # 返回: {"username":"admin","scopes":["openid","profile","api.read"]}
复制代码
六、最佳实践


  • HTTPS:生产情况必须使用TLS
  • Token逾期:access_token发起5-15分钟
  • PKCE:移动端和SPA必须使用
  • 密钥管理:使用Vault等工具存储密钥
七、总结

本文完备演示了Spring Security 6搭建OAuth 2.0授权服务器和资源服务器的全过程。Spring Security 6简化了OAuth 2.0的设置,发起团结Redis实现Token存储,使用数据库存储客户端和用户数据。

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表