冰峰王座 發表於 2026-4-10 14:17:00

Spring Security 6 + OAuth 2.0实战:构建企业级认证授权系统

<h2>一、Spring Security 6 与 OAuth 2.0 概述</h2>
<p>Spring Security 6是Spring Security的最新主版本,全面支持OAuth 2.1和OpenID Connect 1.0。本文将实战演示如何构建一个完整的OAuth 2.0授权服务器和资源服务器,实现安全的API认证与授权。</p>
<h2>二、项目架构设计</h2>
<pre><code>┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
│   客户端应用   │────▶│OAuth 2.0      │────▶│   资源服务器    │
│(Vue/React)    │◀────│授权服务器      │◀────│(REST API)    │
└─────────────────┘   └─────────────────┘   └─────────────────┘
         │                     │                     │
         └───────────────────────┴───────────────────────┘
                  JWT Token 认证流程</code></pre>
<h2>三、授权服务器搭建</h2>
<h3>3.1 添加依赖</h3>
<pre><code>&lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
      &lt;artifactId&gt;spring-security-oauth2-authorization-server&lt;/artifactId&gt;
      &lt;version&gt;1.3.0&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
<h3>3.2 授权服务器配置</h3>
<pre><code>@Configuration
@EnableWebSecurity
public class AuthorizationServerConfig {
    @Bean @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
      OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
      http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults());
      return http.build();
    }
    @Bean @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
      http.authorizeHttpRequests(auth -&gt; auth.requestMatchers("/login").permitAll().anyRequest().authenticated())
            .formLogin(Customizer.withDefaults());
      return http.build();
    }
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
      RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
            .clientId("my-client").clientSecret("{noop}my-secret")
            .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .redirectUri("http://127.0.0.1:8080/login/oauth2/code/my-client")
            .scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).scope("api.read").scope("api.write")
            .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();
      return new InMemoryRegisteredClientRepository(client);
    }
    @Bean
    public JWKSource&lt;SecurityContext&gt; jwkSource() {
      RSAKey rsaKey = generateRsaKey();
      return (jwkSelector, context) -&gt; jwkSelector.select(new JWKSet(rsaKey));
    }
    private static RSAKey generateRsaKey() {
      try {
            KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
            return new RSAKey.Builder((RSAPublicKey)keyPair.getPublic())
                .privateKey((RSAPrivateKey)keyPair.getPrivate()).keyID(UUID.randomUUID().toString()).build();
      } catch (Exception e) { throw new IllegalStateException(e); }
    }
}</code></pre>
<h2>四、资源服务器搭建</h2>
<h3>4.1 配置文件</h3>
<pre><code>spring:
security:
    oauth2:
      resourceserver:
      jwt:
          issuer-uri: http://localhost:9000
          jwk-set-uri: http://localhost:9000/.well-known/jwks.json</code></pre>
<h3>4.2 安全配置</h3>
<pre><code>@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      http.authorizeHttpRequests(auth -&gt; auth
            .requestMatchers("/api/public/**").permitAll()
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated())
            .oauth2ResourceServer(oauth2 -&gt; oauth2.jwt(Customizer.withDefaults()));
      return http.build();
    }
}</code></pre>
<h3>4.3 受保护API示例</h3>
<pre><code>@RestController
@RequestMapping("/api")
public class ApiController {
    @GetMapping("/user/profile")
    public Map&lt;String, Object&gt; userProfile(@AuthenticationPrincipal Jwt jwt) {
      return Map.of("username", jwt.getSubject(), "scopes", jwt.getClaimAsStringList("scope"));
    }
    @GetMapping("/admin/data")
    @PreAuthorize("hasRole('ADMIN')")
    public String adminData() { return "Admin only data"; }
}</code></pre>
<h2>五、客户端测试</h2>
<h3>5.1 获取Token</h3>
<pre><code>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"

# 返回: {"access_token":"eyJ...","token_type":"Bearer","expires_in":300}</code></pre>
<h3>5.2 调用API</h3>
<pre><code>curl -H "Authorization: Bearer eyJ..." http://localhost:8081/api/user/profile
# 返回: {"username":"admin","scopes":["openid","profile","api.read"]}</code></pre>
<h2>六、最佳实践</h2>
<ol>
<li><strong>HTTPS</strong>:生产环境必须使用TLS</li>
<li><strong>Token过期</strong>:access_token建议5-15分钟</li>
<li><strong>PKCE</strong>:移动端和SPA必须使用</li>
<li><strong>密钥管理</strong>:使用Vault等工具存储密钥</li>
</ol>
<h2>七、总结</h2>
<p>本文完整演示了Spring Security 6搭建OAuth 2.0授权服务器和资源服务器的全过程。Spring Security 6简化了OAuth 2.0的配置,建议结合Redis实现Token存储,使用数据库存储客户端和用户数据。</p>

</div>
<div id="MySignature" role="contentinfo">
   

---

📌 **如果觉得文章对你有帮助,欢迎点赞👍收藏⭐!**

💬 有问题或建议?欢迎在评论区留言讨论~

🔗 更多技术干货请关注作者:弥烟袅绕

📚 本文地址:https://www.cnblogs.com/czlws/p/19846673/spring-security-oauth2-tutorial-2026<br><br>
来源:https://www.cnblogs.com/czlws/p/19846673/spring-security-oauth2-tutorial-2026
頁: [1]
查看完整版本: Spring Security 6 + OAuth 2.0实战:构建企业级认证授权系统