芋道开源项目开放平台接入指南(实现客户端 client_credentials 模式)

芋道开源项目开放平台接入指南

🔧 核心实现说明

修改的关键文件

1. OAuth2GrantServiceImpl.java

文件路径: yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java

实现的核心方法: grantClientCredentials

@Override
public OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes) {
    // 1. 获取客户端信息
    OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId);

    // 2. 处理scope逻辑
    List<String> finalScopes = determineFinalScopes(client, scopes);

    // 3. 创建令牌(使用虚拟用户ID,仅用于标识客户端令牌)
    Long virtualUserId = -1L; // 使用负数表示这是客户端令牌,不是真实用户
    return oauth2TokenService.createAccessToken(virtualUserId, UserTypeEnum.ADMIN.getValue(),
            clientId, finalScopes);
}

private List<String> determineFinalScopes(OAuth2ClientDO client, List<String> requestedScopes) {
    List<String> clientScopes = client.getScopes();

    // 如果没有请求特定scope,使用客户端配置的所有scope
    if (CollUtil.isEmpty(requestedScopes)) {
        log.info("[grantClientCredentials] 未指定scope,使用客户端配置的所有权限: {}", clientScopes);
        return clientScopes;
    }

    // 如果请求了特定scope,验证是否在允许范围内
    for (String requestedScope : requestedScopes) {
        if (!clientScopes.contains(requestedScope)) {
            throw exception(OAUTH2_CLIENT_SCOPE_OVER);
        }
    }

    log.info("[grantClientCredentials] 使用请求的scope: {}", requestedScopes);
    return requestedScopes;
}

实现特点:

  • ✅ 支持OAuth2 client_credentials模式
  • ✅ 支持可选scope参数(不传时使用客户端配置的所有权限)
  • ✅ 传scope时验证是否在客户端允许范围内
  • ✅ 使用虚拟用户ID(-1)避免用户绑定复杂性
  • ✅ 完整的日志记录和错误处理
2. OAuth2TokenServiceImpl.java

修改内容:buildUserInfo方法中添加对虚拟用户ID的处理

private Map<String, String> buildUserInfo(Long userId, Integer userType) {
    // 处理客户端模式(client_credentials)的情况
    if (userId == -1L) {
        return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, "开放API客户端")
                .put(LoginUser.INFO_KEY_DEPT_ID, null).build();
    }

    // 其他用户类型的处理逻辑...
}

📖 项目简介

本文档基于芋道开源项目(yudao-cloud),为第三方开发者提供完整的开放平台API接入指南。芋道开源项目是一套全部开源的企业级快速开发平台,采用现代化的架构设计,支持多租户、微服务等特性。

🚀 开放平台特性

核心特性

  • 标准OAuth2认证:基于OAuth2 client_credentials模式
  • 灵活权限控制:通过scope配置精确控制API访问权限
  • 简化接入流程:支持可选scope参数,降低接入门槛
  • 安全可靠:访问令牌短期有效,支持自动刷新机制
  • 完整监控:提供访问日志、错误统计等监控能力

技术架构

  • 认证方式:OAuth2 client_credentials
  • 权限模型:基于scope的资源访问控制
  • 令牌格式:JWT或UUID格式访问令牌
  • 传输协议:HTTPS加密传输
  • 数据格式:JSON格式请求和响应

🔧 快速开始

1. 获取客户端凭证

联系管理员获取以下信息:

  • client_id:客户端标识符
  • client_secret:客户端密钥
  • scopes:授权范围(如:device:read, device:write, data:read, data:write)

2. 获取访问令牌

方式一:使用所有配置权限(推荐新手)
curl -X POST "https://your-domain.com/admin-api/system/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Basic $(echo -n 'client_id:client_secret' | base64)" \
  -d "grant_type=client_credentials"
方式二:指定特定权限范围(推荐生产环境)
curl -X POST "https://your-domain.com/admin-api/system/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Basic $(echo -n 'client_id:client_secret' | base64)" \
  -d "grant_type=client_credentials&scope=device:read,data:read"
响应示例
{
  "code": 0,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 7200,
    "scope": "device:read device:write"
  },
  "msg": "操作成功"
}

3. 调用开放API

使用获取到的访问令牌调用API:

curl -X GET "https://your-domain.com/admin-api/open-api/device/info?deviceId=123" \
  -H "Authorization: Bearer {access_token}"

📋 API接口文档

设备管理API

获取设备信息
  • 接口地址GET /admin-api/open-api/device/info
  • 所需权限device:read
  • 请求参数
    • deviceId(必填):设备ID

请求示例:

curl -X GET "https://api.example.com/admin-api/open-api/device/info?deviceId=123" \
  -H "Authorization: Bearer {access_token}"

响应示例:

{
  "code": 0,
  "data": {
    "deviceId": "123",
    "deviceName": "温度传感器-001",
    "deviceType": "温度传感器",
    "status": "在线",
    "lastUpdateTime": "2024-01-15T10:30:00"
  },
  "msg": "操作成功"
}
获取设备列表
  • 接口地址GET /admin-api/open-api/device/list
  • 所需权限device:read
  • 请求参数
    • pageNo(可选):页码,默认1
    • pageSize(可选):每页大小,默认10
上报设备数据
  • 接口地址POST /admin-api/open-api/device/data
  • 所需权限device:write
  • 请求体:JSON格式设备数据

请求示例:

curl -X POST "https://api.example.com/admin-api/open-api/device/data" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "123",
    "temperature": 25.5,
    "humidity": 60.2,
    "timestamp": "2024-01-15T10:30:00"
  }'
更新设备状态
  • 接口地址PUT /admin-api/open-api/device/status
  • 所需权限device:write
  • 请求体:包含deviceId和status的JSON对象

🔐 权限范围说明

可用的Scope权限

Scope说明适用接口
device:read设备读取权限设备信息查询、设备列表获取
device:write设备写入权限设备数据上报、设备状态更新
data:read数据读取权限历史数据查询、统计数据获取
data:write数据写入权限数据上报、数据导入

权限组合建议

只读监控应用:

scopes: ["device:read", "data:read"]

设备管理应用:

scopes: ["device:read", "device:write"]

数据采集应用:

scopes: ["device:write", "data:write"]

全功能应用:

scopes: ["device:read", "device:write", "data:read", "data:write"]

⚠️ 错误码说明

认证相关错误

错误码说明解决方案
40001无效的客户端检查client_id和client_secret
40002无效的访问令牌重新获取访问令牌
40003访问令牌已过期使用刷新令牌或重新获取

权限相关错误

错误码说明解决方案
40301授权范围不足联系管理员扩大scope权限
1002020001scope超出范围检查请求的scope是否在配置范围内

业务相关错误

错误码说明解决方案
400请求参数错误检查请求参数格式和必填项
404资源不存在检查请求的资源ID是否正确
500服务器内部错误联系技术支持

🛡️ 安全最佳实践

1. 令牌管理

  • 访问令牌有效期为2小时,建议在过期前30分钟刷新
  • 不要在客户端代码中硬编码client_secret
  • 定期轮换客户端密钥

2. 网络安全

  • 必须使用HTTPS传输
  • 实施IP白名单限制(如需要)
  • 监控异常访问模式

3. 错误处理

  • 实现指数退避重试机制
  • 正确处理令牌过期情况
  • 记录详细的错误日志

📊 监控和限流

调用限制

  • 每个客户端每分钟最多1000次API调用
  • 单个IP每分钟最多500次认证请求
  • 超出限制将返回429错误码

监控指标

  • API调用成功率
  • 平均响应时间
  • 错误率统计
  • 令牌使用情况

📝 更新日志

v1.0.0 (2024-01-15)

  • 初始版本发布
  • 支持OAuth2 client_credentials模式
  • 提供设备管理相关API
  • 实现基于scope的权限控制

芋道开源项目 - 让每个人都能快速搭建企业级应用!

项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

### Spring Security 中使用 `client_credentials` 授权类型的概述 为了在应用程序中启用并使用 OAuth2 的 `client_credentials` 流程,开发者需确保应用服务器已正确配置为OAuth2授权服务器,并设置好相应的客户端详情。此流程允许客户端通过提供自身的凭证来获取访问令牌。 #### 配置 Authorization Server 支持 Client Credentials Grant Type 要使Authorization Server支持Client Credentials授权类型,在Spring Security OAuth项目里应扩展`AuthorizationServerConfigurerAdapter`类,并重写其方法以完成必要的安全性和授权端点配置[^1]: ```java @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private final AuthenticationManager authenticationManager; @Autowired public AuthorizationServerConfig(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("my-trusted-client") .authorizedGrantTypes("client_credentials") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read", "write") .resourceIds("oauth2-resource") .accessTokenValiditySeconds(3600 * 8) .secret("{noop}secret"); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } } ``` 上述代码片段展示了如何定义内存中的客户端以及指定该客户端可以使用的授权方式为客户凭据(`client_credentials`)模式。同时设置了读取和写入作用域、资源ID、过期时间及密钥等参数[^4]。 #### 获取 Access Token 使用 REST API 请求 一旦完成了以上配置工作,则可以通过发送HTTP POST请求至/token路径下获得access_token: ```bash curl -X POST \ -H 'Content-Type: application/x-www-form-urlencoded' \ -u my-trusted-client:secret \ -d grant_type=client_credentials \ http://localhost:8080/oauth/token ``` 成功响应将会返回JSON对象形式的数据包,其中包含了用于后续API调用的身份验证信息——即`access_token`字段的内容。 #### 客户端配置与保护资源接口 对于想要消费受保护的服务的应用程序来说,除了作为OAuth2客户端外还需要适当地保护自己的RESTful APIs。这通常涉及到声明哪些URL需要身份验证才能被访问,以及具体采用何种策略来进行权限控制等问题。下面是一个简单的例子说明怎样利用Spring Security来做这些事情[^3]: ```java @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated(); } @Bean @Primary public ResourceServerTokenServices tokenService() { RemoteTokenServices service = new RemoteTokenServices(); service.setCheckTokenEndpointUrl("http://localhost:9999/uaa/oauth/check_token"); service.setClientId("my-trusted-client"); service.setClientSecret("secret"); return service; } ``` 这段Java配置指定了只有经过认证后的用户才能够访问位于/api下的所有子路径;另外还创建了一个名为`tokenService()`的方法用来实例化远程令牌服务组件,它负责向授权服务器查询传入的Bearer Tokens的有效性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值