wso2~通过三方IDP的token置换wso2的token
这种授权模式专为输入能力受限或没有浏览器的设备设计比如智能电视、游戏机、IoT设备或命令行工具CLI。工作原理其核心是一个两步过程。设备获取代码设备上的应用首先向授权服务器如 Microsoft Entra ID的/devicecode端点发起请求。服务器会返回一组信息包括一个简短的user_code用户代码和一个verification_uri验证网址。用户授权设备将user_code和verification_uri显示给用户并提示用户在其他设备如个人手机或电脑上打开浏览器访问该网址并输入代码。用户在授权服务器的正规页面上完成身份验证可能包括多因素认证并同意授权。在此期间设备应用会定期轮询授权服务器的令牌端点直到用户完成操作后获取访问令牌和刷新令牌。安全风险与防御需要注意的是此流程可能被用于进行高迷惑性的网络钓鱼攻击称为“设备代码钓鱼”。攻击者会诱导用户在真实的微软登录页面输入由攻击者生成的设备代码从而授权一个恶意应用。防御措施包括在服务器端严格限制应用同意策略、实施条件访问策略如要求来自合规设备以及对用户进行安全教育。 令牌交换授权 (urn:ietf:params:oauth:grant-type:token-exchange)令牌交换授权提供了强大的 interoperability互操作性允许将一个凭证或令牌交换为另一个不同的令牌常用于服务之间的安全调用或身份映射。核心概念它遵循 OAuth Token Exchange 规范使得客户端能够使用一个现有的subject_token主体令牌来换取一个新的、针对不同受众或资源的access_token访问令牌。常见场景服务间调用后端服务A可以使用自己持有的令牌换取一个具有适当权限的、用于调用服务B的访问令牌。权限降级一个高权限的应用在需要调用一个低信任度的服务时可以换一个权限受限的令牌以提升安全性。外部身份提供商集成将外部IDP如Google、Facebook签发的令牌交换为内部系统的令牌从而实现跨域身份联合。用户模拟在严格管控下服务可以换取一个代表特定用户身份的令牌即模拟用户。实施要点令牌交换功能通常默认不开启需要在服务器端如Red Hat Single Sign-On为客户端显式配置精细的权限策略。⚙️ JWT持有者授权 (urn:ietf:params:oauth:grant-type:jwt-bearer)这种授权类型允许客户端直接使用一个预先签名的JWTJSON Web Token作为断言assertion来获取访问令牌。基本流程客户端向授权服务器的令牌端点发起POST请求在请求体中grant_type参数设置为urn:ietf:params:oauth:grant-type:jwt-bearer并同时提供用作断言的assertion参数即JWT本身。授权服务器会验证该JWT的签名、有效期、颁发者等信息验证通过后即颁发所请求的访问令牌。典型应用场景服务账户认证在机器对机器M2M的通信中一个服务可以使用事先配置好的JWT通常基于私钥签名来获取访问令牌无需用户交互。这在CI/CD流水线或后台服务中非常常见。微服务架构在微服务网络中一个服务在收到访问令牌后可以利用此流程向认证服务器换取一个范围scope更窄、专用于访问另一个特定微服务的令牌。下面的表格清晰地对比了这三种授权类型的关键差异。特性设备代码授权 (device_code)令牌交换授权 (token-exchange)JWT持有者授权 (jwt-bearer)主要目的方便输入受限设备上的用户授权实现令牌之间的安全转换和身份委托客户端使用已有的JWT直接获取访问令牌令牌流轮询机制直接交换断言式请求典型应用智能电视、IoT设备、CLI工具服务间调用、权限降级、身份联合机器对机器通信、服务账户、微服务 总结与安全考量选择哪种授权类型完全取决于你的具体应用场景。设备代码授权优化了受限设备的用户体验令牌交换授权为复杂的服务间信任链提供了灵活性而JWT持有者授权则是机器对机器通信的简洁高效方案。在实施这些授权流程时务必关注以下安全最佳实践严格控制权限遵循最小权限原则只为应用授予其必需的最少权限。验证与监控服务器端必须严格验证所有令牌和断言如JWT的签名和有效期并建立日志审计和异常行为监控机制。保护令牌访问令牌和刷新令牌是敏感凭证在传输和存储过程中必须加以保护。wso2中的实战wso2 sp的配置Keycloak中客户端授权范围wso2-role中添加aud的硬编码配置认证grant_type类型keycloak idp的配置keycloak中为客户端开启roles之后如果有用户有客户端的角色会在jwt中多出来aud数组字段也可以为wso2客户端添加自定义的client scope然后为它添加aud的cliamsIDP名称必须与IDP中token的Issuer相同测试span stylecolor:#393a34span stylebackground-color:whitecode classlanguage-nonecurl -X POST https://test-apim.xxx.com/oauth2/token -H Content-Type: application/json -H Content-Type: application/json -u wso2-sp-client-id:wso2-sp-client-secret --basic -d { grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer, assertion: abc.abc.abc, scope: apim:subscribe } /code/span/spanscope参数如果不传默认是default对于apim的开发者平台这个值必须传否则无权限添加应用和订阅api这块功能scope使用你认证能数里的scope还是使用默认的default主要在IDP的Claim Configuration配置中进行设置如图如果keycloak_token过期就返回这个400错误span stylecolor:#393a34span stylebackground-color:whitecode classlanguage-none{ error_description: JSON Web Token is expired., Expiration Time(ms) : 1769413736000, TimeStamp Skew : 0, Current Time : 1769413748585. JWT Rejected and validation terminated, error: invalid_grant } /code/span/span如果成功会返wso2平台的token需要注意这个返回值里scope如果它是default那是没有操作application的权限的span stylecolor:#393a34span stylebackground-color:whitecode classlanguage-none{ access_token: 8b23bf56-f8d2-33fa-9962-f298a797ce94, refresh_token: aad2555-30b0-3591-8c70-b2cdc042cc41, scope: apim:subscribe openid, id_token: , token_type: Bearer, expires_in: 3185 } /code/span/span用户登录成功后会初始化用户表需要注意的是这种urn:ietf:params:oauth:grant-type:jwt-bearer首次登录添加的用户它位于wso2am_db.idn_auth_user表user_name同样是三方社区token中的sub字段而标准oauth的授权码认证后除了在wso2am_db.idn_auth_user表初始化外还在wso2am_share_db.um_user表也会添加一份用户数据。【添加的用户没有订阅者角色导致用户建立的应用无法订阅API】对于上面的um_user中的用户它在carbon平台是可以查询到的它默认是没有subscribe权限的只有everyone权限这时它建立的应用应用是无法订阅api的我们需要同时为um_user的用户初始化角色subscribe这块功能由product-is系统提供所以在共享库wso2am_shared_db里数据表为um_hybrid_role和um_hybrid_user_role。调整源码cargin-apimgt项目org.wso2.carbon.apimgt.impl.issuers.configureForJWTGrantOrExchangeGrant()方法再执行FederatedUserSyncUtil.syncFederatedUserToUMUser(tenantDomain, userName)方法为期添加初始化um_hybrid_user_role的脚本注意当wso2am_share_db.um_user表没有这个用户数据时你再为应用生成consumer_key时调用generate-keys接口会出现错误所以我们需要想办法在wso2am_share_db.um_user表表初始化一条用户数据um_user_name与wso2am_db.idn_auth_user表的user_name保持一致即可即三方IDP的user_id即可默认应用如何创建通过获取用户应用的接口完成后如果没有默认应用会为用户自动创建即初始化下面两张表am_subscriberam_application首次无订阅者和应用时需要调用获取应用接口GET https://test-apim.pkulaw.com/api/am/devportal/v3/applicationsheader Authorization bearer token响应结果没有应该会自动添加默认应用span stylecolor:#393a34span stylebackground-color:whitecode classlanguage-none { count: 1, list: [ { applicationId: 46fd899d-5612-4708-82f7-a768c9d94678, name: 默认应用, throttlingPolicy: Unlimited, description: 系统为您创建的默认应用xxxx, status: APPROVED, groups: [], subscriptionCount: 0, attributes: {}, owner: 819b3483-d859-4f41-854a-907aec27a068, tokenType: DEFAULT, createdTime: 1771910083000, updatedTime: 1771910083000 } ], pagination: { offset: 0, limit: 25, total: 1, next: , previous: } } /code/span/span为应用生成consumer_key和consumer_secret接口前提先为用户初始化wso2am_share_db.um_user表否则会出现错误consumer_key为空等问题span stylecolor:#393a34span stylebackground-color:whitecode classlanguage-none{ code: 900967, message: General Error, description: Server Error Occurred, moreInfo: , error: [] } /code/span/span当接口执行成功后会初始化下面三个数据表am_application_registrationam_application_key_mappingidn_oauth_consumer_appsGET /applications/application_uuid/generate-keysspan stylecolor:#393a34span stylebackground-color:whitecode classlanguage-none{ keyType: PRODUCTION, grantTypesToBeSupported: [ password, client_credentials ], callbackUrl: , additionalProperties: { application_access_token_expiry_time: 36000, user_access_token_expiry_time: 36000, refresh_token_expiry_time: 36000, id_token_expiry_time: 36000, pkceMandatory: false, pkceSupportPlain: false, bypassClientCredentials: false }, keyManager: aefd5cd3-c18a-47f8-91c9-2fa42767b4bf, validityTime: 3600, scopes: [ default ] } /code/span/span生成的am_application_key_mapping表中consumer_key是非空的这个很重要。自动添加默认应用的原理[这些在源码里已经实现],这块不需要调整的源码已支持应用添加consumer_key的生成需要手动调用接口为用户添加了订阅者默认应用应用的consumerKey和consumerSecret等用户可以手动为应该生成tokenSubscriberRegistrationInterceptor是添加订阅者的入口org.wso2.carbon.apimgt.rest.api.util.interceptors.SubscriberRegistrationInterceptorhandleMessage方法订阅被注册后如果没有应用会添加默认认证