1. 概述

在这篇文章中,我们将深入探讨 Spring Security 中的 @EnableResourceServer@EnableOAuth2Sso 注解。

首先会解释 OAuth2 客户端(Client)和资源服务器(Resource Server)的区别。然后介绍这两个注解的作用,并通过一个结合 Zuul 和简单 API 的示例,展示它们的实际用法。

本文假设你已经对 ZuulOAuth2 有一定的了解。如果你是新手,建议先阅读我们的 Zuul 快速入门OAuth2 使用指南

2. OAuth2 客户端 vs 资源服务器

在 OAuth2 协议中定义了四种角色(RFC 6749),我们需要重点关注以下两个:

资源服务器(Resource Server)
需要访问令牌才能允许访问其受保护资源的服务组件。

客户端(Client)
能够从授权服务器获取访问令牌的应用实体。

使用 @EnableResourceServer@EnableOAuth2Sso 注解,可以快速将我们的应用配置为以上两种角色之一:

  • @EnableResourceServer:让应用成为资源服务器 ✅
    Spring 会自动配置如 OAuth2AuthenticationProcessingFilter 等核心组件,用于处理 OAuth2 请求验证。

  • @EnableOAuth2Sso:使应用成为 OAuth2 客户端 ✅
    配置 OAuth2ClientAuthenticationProcessingFilter 等组件,用于与授权服务器交互以获取访问令牌。

🔍 查看源码可更深入了解:

接下来我们构建两个应用来演示这两个注解的使用场景:

  1. Zuul 网关应用(边缘节点):使用 @EnableOAuth2Sso,负责用户认证并转发请求。
  2. API 应用(资源服务):使用 @EnableResourceServer,验证访问令牌后提供受保护资源。

3. Zuul 应用 —— @EnableOAuth2Sso

下面是 Zuul 应用的配置类示例:

@Configuration
@EnableZuulProxy
@EnableOAuth2Sso
@Order(value = 0)
public class AppConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private ResourceServerTokenServices 
      resourceServerTokenServices;

    @Override
    public void configure(HttpSecurity http) throws Exception { 
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/authorization-server-1/**",
              "/login").permitAll()
            .anyRequest().authenticated().and()
            .logout().permitAll().logoutSuccessUrl("/");
    }
}

📌 注意事项:

  • 使用 @EnableOAuth2Sso 后,Spring 会自动注册 OAuth2TokenRelayFilter,它会从用户会话中取出访问令牌,并向下传递。
  • 使用 @Order(0) 是为了确保当前安全配置优先于其他自动配置的安全过滤器链。

⚠️ 坑点提醒:如果同时使用了 @EnableResourceServer,默认情况下它的过滤器顺序(order=3)会高于当前配置(order=100),可能会导致认证逻辑混乱。

下面是相关的 YAML 配置片段:

zuul:
  routes:
    resource-server-mvc-1: /resource-server-mvc-1/**
    authorization-server-1:
      sensitiveHeaders: Authorization
      path: /authorization-server-1/**
      stripPrefix: false
  add-proxy-headers: true

security:
  basic:
    enabled: false
  oauth2:
    sso:
      loginPath: /login
    client:
      accessTokenUri: http://localhost:8769/authorization-server-1/oauth/token
      userAuthorizationUri: /authorization-server-1/oauth/authorize
      clientId: fooClient
      clientSecret: fooSecret
    resource:
      jwt:
        keyValue: "abc"
      id: fooScope
      serviceId: ${PREFIX:}resource

🎯 配置说明:

  • zuul.routes:定义路由规则,控制哪些路径由哪个服务处理。
  • security.oauth2.client:指定授权服务器地址、客户端 ID 和密钥等信息。
  • jwt.keyValue:使用对称加密方式解析 JWT。

4. API 应用 —— @EnableResourceServer

下面是资源服务器的实现代码:

@SpringBootApplication
@EnableResourceServer
@Controller
@RequestMapping("/")
class ResourceServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourceServerApplication.class, args);
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String helloWorld(Principal principal) {
        return "Hello " + principal.getName();
    }
}

这是一个非常简单的 REST 接口,返回当前用户的名称。

对应配置文件如下:

security:
  basic:
    enabled: false
  oauth2:
    resource:
      jwt:
        keyValue: "abc"
      id: fooScope
      service-id: ${PREFIX:}resource

🔑 关键点:

  • 必须携带有效的 OAuth2 访问令牌才能访问此接口。
  • 在网关层完成认证后,访问令牌会被传递到资源服务器进行校验。

5. 总结

这篇文章详细讲解了 @EnableOAuth2Sso@EnableResourceServer 的用途及区别,并通过 Zuul + Resource Server 的实际例子展示了它们如何协同工作。

💡 示例项目完整代码可在 GitHub 获取。

本地运行时可通过如下地址测试:

http://192.168.1.67:8765/resource-server-mvc-1

📌 一句话总结

  • @EnableOAuth2Sso:让应用变成 OAuth2 客户端,负责登录认证。
  • @EnableResourceServer:让应用变成资源服务器,负责资源保护和权限校验。

原始标题:OAuth2 - @EnableResourceServer vs @EnableOAuth2Sso